Merge branch 'master' of github.com:awakecoding/FreeRDP into egfx
Conflicts: channels/drdynvc/client/dvcman.c client/X11/xf_client.c include/freerdp/dvc.h
This commit is contained in:
commit
6f9a256c5c
@ -417,9 +417,13 @@ set(FFMPEG_FEATURE_TYPE "RECOMMENDED")
|
||||
set(FFMPEG_FEATURE_PURPOSE "multimedia")
|
||||
set(FFMPEG_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
|
||||
|
||||
set(GSTREAMER_FEATURE_TYPE "RECOMMENDED")
|
||||
set(GSTREAMER_FEATURE_PURPOSE "multimedia")
|
||||
set(GSTREAMER_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
|
||||
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
|
||||
set(GSTREAMER_0_10_FEATURE_PURPOSE "multimedia")
|
||||
set(GSTREAMER_0_10_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback, gstreamer 0.10 version")
|
||||
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "RECOMMENDED")
|
||||
set(GSTREAMER_1_0_FEATURE_PURPOSE "multimedia")
|
||||
set(GSTREAMER_1_0_FEATURE_DESCRIPTION "multimedia redirection, audio and video playback")
|
||||
|
||||
set(IPP_FEATURE_TYPE "OPTIONAL")
|
||||
set(IPP_FEATURE_PURPOSE "performance")
|
||||
@ -442,14 +446,15 @@ if(WIN32)
|
||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_0_10_FEATURE_TYPE "OPTIONAL")
|
||||
set(OPENSLES_FEATURE_TYPE "DISABLED")
|
||||
endif()
|
||||
|
||||
if(APPLE)
|
||||
set(DIRECTFB_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "OPTIONAL")
|
||||
set(GSTREAMER_FEATURE_TYPE "OPTIONAL")
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "OPTIONAL")
|
||||
set(X11_FEATURE_TYPE "OPTIONAL")
|
||||
if(IOS)
|
||||
set(X11_FEATURE_TYPE "DISABLED")
|
||||
@ -457,7 +462,8 @@ if(APPLE)
|
||||
set(PULSE_FEATURE_TYPE "DISABLED")
|
||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED")
|
||||
endif()
|
||||
set(OPENSLES_FEATURE_TYPE "DISABLED")
|
||||
endif()
|
||||
@ -470,7 +476,8 @@ if(ANDROID)
|
||||
set(CUPS_FEATURE_TYPE "DISABLED")
|
||||
set(PCSC_FEATURE_TYPE "DISABLED")
|
||||
set(FFMPEG_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_1_0_FEATURE_TYPE "DISABLED")
|
||||
set(GSTREAMER_0_10_FEATURE_TYPE "DISABLED")
|
||||
set(OPENSLES_FEATURE_TYPE "REQUIRED")
|
||||
endif()
|
||||
|
||||
@ -492,7 +499,9 @@ find_feature(Cups ${CUPS_FEATURE_TYPE} ${CUPS_FEATURE_PURPOSE} ${CUPS_FEATURE_DE
|
||||
find_feature(PCSC ${PCSC_FEATURE_TYPE} ${PCSC_FEATURE_PURPOSE} ${PCSC_FEATURE_DESCRIPTION})
|
||||
|
||||
find_feature(FFmpeg ${FFMPEG_FEATURE_TYPE} ${FFMPEG_FEATURE_PURPOSE} ${FFMPEG_FEATURE_DESCRIPTION})
|
||||
find_feature(Gstreamer ${GSTREAMER_FEATURE_TYPE} ${GSTREAMER_FEATURE_PURPOSE} ${GSTREAMER_FEATURE_DESCRIPTION})
|
||||
|
||||
find_feature(GStreamer_0_10 ${GSTREAMER_0_10_FEATURE_TYPE} ${GSTREAMER_0_10_FEATURE_PURPOSE} ${GSTREAMER_0_10_FEATURE_DESCRIPTION})
|
||||
find_feature(GStreamer_1_0 ${GSTREAMER_1_0_FEATURE_TYPE} ${GSTREAMER_1_0_FEATURE_PURPOSE} ${GSTREAMER_1_0_FEATURE_DESCRIPTION})
|
||||
|
||||
find_feature(JPEG ${JPEG_FEATURE_TYPE} ${JPEG_FEATURE_PURPOSE} ${JPEG_FEATURE_DESCRIPTION})
|
||||
find_feature(GSM ${GSM_FEATURE_TYPE} ${GSM_FEATURE_PURPOSE} ${GSM_FEATURE_DESCRIPTION})
|
||||
|
@ -29,7 +29,6 @@
|
||||
#include <winpr/stream.h>
|
||||
|
||||
#include <freerdp/constants.h>
|
||||
#include <freerdp/utils/svc_plugin.h>
|
||||
|
||||
#include "dvcman.h"
|
||||
#include "drdynvc_types.h"
|
||||
@ -298,8 +297,7 @@ static int drdynvc_process_data_first(drdynvcPlugin* drdynvc, int Sp, int cbChId
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
|
||||
Stream_Pointer(s), Stream_GetRemainingLength(s));
|
||||
return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId, s);
|
||||
}
|
||||
|
||||
static int drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStream* s)
|
||||
@ -309,8 +307,7 @@ static int drdynvc_process_data(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStr
|
||||
ChannelId = drdynvc_read_variable_uint(s, cbChId);
|
||||
DEBUG_DVC("ChannelId=%d", ChannelId);
|
||||
|
||||
return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId,
|
||||
Stream_Pointer(s), Stream_GetRemainingLength(s));
|
||||
return dvcman_receive_channel_data(drdynvc->channel_mgr, ChannelId, s);
|
||||
}
|
||||
|
||||
static int drdynvc_process_close_request(drdynvcPlugin* drdynvc, int Sp, int cbChId, wStream* s)
|
||||
@ -382,8 +379,6 @@ static void drdynvc_process_receive(rdpSvcPlugin* plugin, wStream* s)
|
||||
DEBUG_WARN("unknown drdynvc cmd 0x%x", Cmd);
|
||||
break;
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
|
||||
static void drdynvc_process_connect(rdpSvcPlugin* plugin)
|
||||
@ -425,6 +420,8 @@ static void drdynvc_process_terminate(rdpSvcPlugin* plugin)
|
||||
if (drdynvc->channel_mgr)
|
||||
dvcman_free(drdynvc->channel_mgr);
|
||||
|
||||
svc_plugin_terminate(plugin);
|
||||
|
||||
free(drdynvc);
|
||||
}
|
||||
|
||||
@ -482,3 +479,4 @@ BOOL VCAPITYPE VirtualChannelEntry(PCHANNEL_ENTRY_POINTS pEntryPoints)
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -195,8 +195,7 @@ IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
|
||||
{
|
||||
DVCMAN* dvcman;
|
||||
|
||||
dvcman = (DVCMAN*) malloc(sizeof(DVCMAN));
|
||||
ZeroMemory(dvcman, sizeof(DVCMAN));
|
||||
dvcman = (DVCMAN*) calloc(1, sizeof(DVCMAN));
|
||||
|
||||
dvcman->iface.CreateListener = dvcman_create_listener;
|
||||
dvcman->iface.PushEvent = dvcman_push_event;
|
||||
@ -204,6 +203,7 @@ IWTSVirtualChannelManager* dvcman_new(drdynvcPlugin* plugin)
|
||||
dvcman->iface.GetChannelId = dvcman_get_channel_id;
|
||||
dvcman->drdynvc = plugin;
|
||||
dvcman->channels = ArrayList_New(TRUE);
|
||||
dvcman->pool = StreamPool_New(TRUE, 10);
|
||||
|
||||
return (IWTSVirtualChannelManager*) dvcman;
|
||||
}
|
||||
@ -278,6 +278,7 @@ void dvcman_free(IWTSVirtualChannelManager* pChannelMgr)
|
||||
pPlugin->Terminated(pPlugin);
|
||||
}
|
||||
|
||||
StreamPool_Free(dvcman->pool);
|
||||
free(dvcman);
|
||||
}
|
||||
|
||||
@ -424,7 +425,7 @@ int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelI
|
||||
|
||||
if (channel->dvc_data)
|
||||
{
|
||||
Stream_Free(channel->dvc_data, TRUE);
|
||||
Stream_Release(channel->dvc_data);
|
||||
channel->dvc_data = NULL;
|
||||
}
|
||||
|
||||
@ -457,17 +458,19 @@ int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UI
|
||||
}
|
||||
|
||||
if (channel->dvc_data)
|
||||
Stream_Free(channel->dvc_data, TRUE);
|
||||
Stream_Release(channel->dvc_data);
|
||||
|
||||
channel->dvc_data = Stream_New(NULL, length);
|
||||
channel->dvc_data = StreamPool_Take(channel->dvcman->pool, length);
|
||||
Stream_AddRef(channel->dvc_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, BYTE* data, UINT32 data_size)
|
||||
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, wStream* data)
|
||||
{
|
||||
int error = 0;
|
||||
DVCMAN_CHANNEL* channel;
|
||||
UINT32 dataSize = Stream_GetRemainingLength(data);
|
||||
|
||||
channel = (DVCMAN_CHANNEL*) dvcman_find_channel_by_id(pChannelMgr, ChannelId);
|
||||
|
||||
@ -480,28 +483,30 @@ int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 C
|
||||
if (channel->dvc_data)
|
||||
{
|
||||
/* Fragmented data */
|
||||
if (Stream_GetPosition(channel->dvc_data) + data_size > (UINT32) Stream_Capacity(channel->dvc_data))
|
||||
if (Stream_GetPosition(channel->dvc_data) + dataSize > (UINT32) Stream_Capacity(channel->dvc_data))
|
||||
{
|
||||
DEBUG_WARN("data exceeding declared length!");
|
||||
Stream_Free(channel->dvc_data, TRUE);
|
||||
Stream_Release(channel->dvc_data);
|
||||
channel->dvc_data = NULL;
|
||||
return 1;
|
||||
}
|
||||
|
||||
Stream_Write(channel->dvc_data, data, data_size);
|
||||
Stream_Write(channel->dvc_data, Stream_Pointer(data), dataSize);
|
||||
|
||||
if (((size_t) Stream_GetPosition(channel->dvc_data)) >= Stream_Capacity(channel->dvc_data))
|
||||
{
|
||||
error = channel->channel_callback->OnDataReceived(channel->channel_callback,
|
||||
Stream_Capacity(channel->dvc_data), Stream_Buffer(channel->dvc_data));
|
||||
Stream_Free(channel->dvc_data, TRUE);
|
||||
Stream_SealLength(channel->dvc_data);
|
||||
Stream_SetPosition(channel->dvc_data, 0);
|
||||
error = channel->channel_callback->OnDataReceived(channel->channel_callback, channel->dvc_data);
|
||||
Stream_Release(channel->dvc_data);
|
||||
channel->dvc_data = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
error = channel->channel_callback->OnDataReceived(channel->channel_callback, data_size, data);
|
||||
error = channel->channel_callback->OnDataReceived(channel->channel_callback, data);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
|
@ -43,6 +43,7 @@ struct _DVCMAN
|
||||
int num_listeners;
|
||||
|
||||
wArrayList* channels;
|
||||
wStreamPool* pool;
|
||||
};
|
||||
typedef struct _DVCMAN DVCMAN;
|
||||
|
||||
@ -90,7 +91,7 @@ int dvcman_create_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 Channel
|
||||
int dvcman_open_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId);
|
||||
int dvcman_close_channel(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId);
|
||||
int dvcman_receive_channel_data_first(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, UINT32 length);
|
||||
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, BYTE* data, UINT32 data_size);
|
||||
int dvcman_receive_channel_data(IWTSVirtualChannelManager* pChannelMgr, UINT32 ChannelId, wStream *data);
|
||||
|
||||
void* dvcman_get_channel_interface_by_name(IWTSVirtualChannelManager* pChannelMgr, const char* ChannelName);
|
||||
|
||||
|
@ -55,7 +55,7 @@ if(WITH_FFMPEG)
|
||||
add_channel_client_subsystem(${MODULE_PREFIX} ${CHANNEL_NAME} "ffmpeg" "decoder")
|
||||
endif()
|
||||
|
||||
if(WITH_GSTREAMER)
|
||||
if(WITH_GSTREAMER_0_10 OR WITH_GSTREAMER_1_0)
|
||||
set(XRANDR_FEATURE_TYPE "REQUIRED")
|
||||
set(XRANDR_FEATURE_PURPOSE "X11 randr")
|
||||
set(XRANDR_FEATURE_DESCRIPTION "X11 randr extension")
|
||||
|
@ -24,7 +24,6 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
@ -41,225 +40,194 @@ typedef struct _TSMFALSAAudioDevice
|
||||
ITSMFAudioDevice iface;
|
||||
|
||||
char device[32];
|
||||
snd_pcm_t* out_handle;
|
||||
snd_pcm_t *out_handle;
|
||||
UINT32 source_rate;
|
||||
UINT32 actual_rate;
|
||||
UINT32 source_channels;
|
||||
UINT32 actual_channels;
|
||||
UINT32 bytes_per_sample;
|
||||
|
||||
FREERDP_DSP_CONTEXT* dsp_context;
|
||||
FREERDP_DSP_CONTEXT *dsp_context;
|
||||
} TSMFAlsaAudioDevice;
|
||||
|
||||
static BOOL tsmf_alsa_open_device(TSMFAlsaAudioDevice* alsa)
|
||||
static BOOL tsmf_alsa_open_device(TSMFAlsaAudioDevice *alsa)
|
||||
{
|
||||
int error;
|
||||
|
||||
error = snd_pcm_open(&alsa->out_handle, alsa->device, SND_PCM_STREAM_PLAYBACK, 0);
|
||||
|
||||
if (error < 0)
|
||||
if(error < 0)
|
||||
{
|
||||
DEBUG_WARN("failed to open device %s", alsa->device);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DEBUG_DVC("open device %s", alsa->device);
|
||||
DEBUG_TSMF("open device %s", alsa->device);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_alsa_open(ITSMFAudioDevice* audio, const char* device)
|
||||
static BOOL tsmf_alsa_open(ITSMFAudioDevice *audio, const char *device)
|
||||
{
|
||||
TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio;
|
||||
|
||||
if (!device)
|
||||
TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio;
|
||||
if(!device)
|
||||
{
|
||||
if (!alsa->device[0])
|
||||
if(!alsa->device[0])
|
||||
strncpy(alsa->device, "default", sizeof(alsa->device));
|
||||
}
|
||||
else
|
||||
{
|
||||
strncpy(alsa->device, device, sizeof(alsa->device));
|
||||
}
|
||||
|
||||
return tsmf_alsa_open_device(alsa);
|
||||
}
|
||||
|
||||
static BOOL tsmf_alsa_set_format(ITSMFAudioDevice* audio,
|
||||
UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample)
|
||||
static BOOL tsmf_alsa_set_format(ITSMFAudioDevice *audio,
|
||||
UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample)
|
||||
{
|
||||
int error;
|
||||
snd_pcm_uframes_t frames;
|
||||
snd_pcm_hw_params_t* hw_params;
|
||||
snd_pcm_sw_params_t* sw_params;
|
||||
TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio;
|
||||
|
||||
if (!alsa->out_handle)
|
||||
snd_pcm_hw_params_t *hw_params;
|
||||
snd_pcm_sw_params_t *sw_params;
|
||||
TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio;
|
||||
if(!alsa->out_handle)
|
||||
return FALSE;
|
||||
|
||||
snd_pcm_drop(alsa->out_handle);
|
||||
|
||||
alsa->actual_rate = alsa->source_rate = sample_rate;
|
||||
alsa->actual_channels = alsa->source_channels = channels;
|
||||
alsa->bytes_per_sample = bits_per_sample / 8;
|
||||
|
||||
error = snd_pcm_hw_params_malloc(&hw_params);
|
||||
|
||||
if (error < 0)
|
||||
if(error < 0)
|
||||
{
|
||||
DEBUG_WARN("snd_pcm_hw_params_malloc failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
snd_pcm_hw_params_any(alsa->out_handle, hw_params);
|
||||
snd_pcm_hw_params_set_access(alsa->out_handle, hw_params,
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
SND_PCM_ACCESS_RW_INTERLEAVED);
|
||||
snd_pcm_hw_params_set_format(alsa->out_handle, hw_params,
|
||||
SND_PCM_FORMAT_S16_LE);
|
||||
SND_PCM_FORMAT_S16_LE);
|
||||
snd_pcm_hw_params_set_rate_near(alsa->out_handle, hw_params,
|
||||
&alsa->actual_rate, NULL);
|
||||
&alsa->actual_rate, NULL);
|
||||
snd_pcm_hw_params_set_channels_near(alsa->out_handle, hw_params,
|
||||
&alsa->actual_channels);
|
||||
&alsa->actual_channels);
|
||||
frames = sample_rate;
|
||||
snd_pcm_hw_params_set_buffer_size_near(alsa->out_handle, hw_params,
|
||||
&frames);
|
||||
&frames);
|
||||
snd_pcm_hw_params(alsa->out_handle, hw_params);
|
||||
snd_pcm_hw_params_free(hw_params);
|
||||
|
||||
error = snd_pcm_sw_params_malloc(&sw_params);
|
||||
|
||||
if (error < 0)
|
||||
if(error < 0)
|
||||
{
|
||||
DEBUG_WARN("snd_pcm_sw_params_malloc");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
snd_pcm_sw_params_current(alsa->out_handle, sw_params);
|
||||
snd_pcm_sw_params_set_start_threshold(alsa->out_handle, sw_params,
|
||||
frames / 2);
|
||||
frames / 2);
|
||||
snd_pcm_sw_params(alsa->out_handle, sw_params);
|
||||
snd_pcm_sw_params_free(sw_params);
|
||||
|
||||
snd_pcm_prepare(alsa->out_handle);
|
||||
|
||||
DEBUG_DVC("sample_rate %d channels %d bits_per_sample %d",
|
||||
sample_rate, channels, bits_per_sample);
|
||||
DEBUG_DVC("hardware buffer %d frames", (int)frames);
|
||||
|
||||
if ((alsa->actual_rate != alsa->source_rate) ||
|
||||
(alsa->actual_channels != alsa->source_channels))
|
||||
DEBUG_TSMF("sample_rate %d channels %d bits_per_sample %d",
|
||||
sample_rate, channels, bits_per_sample);
|
||||
DEBUG_TSMF("hardware buffer %d frames", (int)frames);
|
||||
if((alsa->actual_rate != alsa->source_rate) ||
|
||||
(alsa->actual_channels != alsa->source_channels))
|
||||
{
|
||||
DEBUG_DVC("actual rate %d / channel %d is different "
|
||||
"from source rate %d / channel %d, resampling required.",
|
||||
alsa->actual_rate, alsa->actual_channels,
|
||||
alsa->source_rate, alsa->source_channels);
|
||||
DEBUG_TSMF("actual rate %d / channel %d is different "
|
||||
"from source rate %d / channel %d, resampling required.",
|
||||
alsa->actual_rate, alsa->actual_channels,
|
||||
alsa->source_rate, alsa->source_channels);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_alsa_play(ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size)
|
||||
static BOOL tsmf_alsa_play(ITSMFAudioDevice *audio, BYTE *data, UINT32 data_size)
|
||||
{
|
||||
int len;
|
||||
int error;
|
||||
int frames;
|
||||
BYTE* end;
|
||||
BYTE* src;
|
||||
BYTE* pindex;
|
||||
BYTE *end;
|
||||
BYTE *src;
|
||||
BYTE *pindex;
|
||||
int rbytes_per_frame;
|
||||
int sbytes_per_frame;
|
||||
TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio;
|
||||
|
||||
DEBUG_DVC("data_size %d", data_size);
|
||||
|
||||
if (alsa->out_handle)
|
||||
TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio;
|
||||
DEBUG_TSMF("data_size %d", data_size);
|
||||
if(alsa->out_handle)
|
||||
{
|
||||
sbytes_per_frame = alsa->source_channels * alsa->bytes_per_sample;
|
||||
rbytes_per_frame = alsa->actual_channels * alsa->bytes_per_sample;
|
||||
|
||||
if ((alsa->source_rate == alsa->actual_rate) &&
|
||||
(alsa->source_channels == alsa->actual_channels))
|
||||
if((alsa->source_rate == alsa->actual_rate) &&
|
||||
(alsa->source_channels == alsa->actual_channels))
|
||||
{
|
||||
src = data;
|
||||
}
|
||||
else
|
||||
{
|
||||
alsa->dsp_context->resample(alsa->dsp_context, data, alsa->bytes_per_sample,
|
||||
alsa->source_channels, alsa->source_rate, data_size / sbytes_per_frame,
|
||||
alsa->actual_channels, alsa->actual_rate);
|
||||
alsa->source_channels, alsa->source_rate, data_size / sbytes_per_frame,
|
||||
alsa->actual_channels, alsa->actual_rate);
|
||||
frames = alsa->dsp_context->resampled_frames;
|
||||
DEBUG_DVC("resampled %d frames at %d to %d frames at %d",
|
||||
data_size / sbytes_per_frame, alsa->source_rate, frames, alsa->actual_rate);
|
||||
DEBUG_TSMF("resampled %d frames at %d to %d frames at %d",
|
||||
data_size / sbytes_per_frame, alsa->source_rate, frames, alsa->actual_rate);
|
||||
data_size = frames * rbytes_per_frame;
|
||||
src = alsa->dsp_context->resampled_buffer;
|
||||
}
|
||||
|
||||
pindex = src;
|
||||
end = pindex + data_size;
|
||||
while (pindex < end)
|
||||
while(pindex < end)
|
||||
{
|
||||
len = end - pindex;
|
||||
frames = len / rbytes_per_frame;
|
||||
error = snd_pcm_writei(alsa->out_handle, pindex, frames);
|
||||
|
||||
if (error == -EPIPE)
|
||||
if(error == -EPIPE)
|
||||
{
|
||||
snd_pcm_recover(alsa->out_handle, error, 0);
|
||||
error = 0;
|
||||
}
|
||||
else if (error < 0)
|
||||
{
|
||||
DEBUG_DVC("error len %d", error);
|
||||
snd_pcm_close(alsa->out_handle);
|
||||
alsa->out_handle = 0;
|
||||
tsmf_alsa_open_device(alsa);
|
||||
else
|
||||
if(error < 0)
|
||||
{
|
||||
DEBUG_TSMF("error len %d", error);
|
||||
snd_pcm_close(alsa->out_handle);
|
||||
alsa->out_handle = 0;
|
||||
tsmf_alsa_open_device(alsa);
|
||||
break;
|
||||
}
|
||||
DEBUG_TSMF("%d frames played.", error);
|
||||
if(error == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
DEBUG_DVC("%d frames played.", error);
|
||||
|
||||
if (error == 0)
|
||||
break;
|
||||
|
||||
pindex += error * rbytes_per_frame;
|
||||
}
|
||||
}
|
||||
free(data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static UINT64 tsmf_alsa_get_latency(ITSMFAudioDevice* audio)
|
||||
static UINT64 tsmf_alsa_get_latency(ITSMFAudioDevice *audio)
|
||||
{
|
||||
UINT64 latency = 0;
|
||||
snd_pcm_sframes_t frames = 0;
|
||||
TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio;
|
||||
|
||||
if (alsa->out_handle && alsa->actual_rate > 0 &&
|
||||
snd_pcm_delay(alsa->out_handle, &frames) == 0 &&
|
||||
frames > 0)
|
||||
TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio;
|
||||
if(alsa->out_handle && alsa->actual_rate > 0 &&
|
||||
snd_pcm_delay(alsa->out_handle, &frames) == 0 &&
|
||||
frames > 0)
|
||||
{
|
||||
latency = ((UINT64)frames) * 10000000LL / (UINT64) alsa->actual_rate;
|
||||
}
|
||||
|
||||
return latency;
|
||||
}
|
||||
|
||||
static void tsmf_alsa_flush(ITSMFAudioDevice* audio)
|
||||
static void tsmf_alsa_flush(ITSMFAudioDevice *audio)
|
||||
{
|
||||
}
|
||||
|
||||
static void tsmf_alsa_free(ITSMFAudioDevice* audio)
|
||||
static void tsmf_alsa_free(ITSMFAudioDevice *audio)
|
||||
{
|
||||
TSMFAlsaAudioDevice* alsa = (TSMFAlsaAudioDevice*) audio;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
if (alsa->out_handle)
|
||||
TSMFAlsaAudioDevice *alsa = (TSMFAlsaAudioDevice *) audio;
|
||||
DEBUG_TSMF("");
|
||||
if(alsa->out_handle)
|
||||
{
|
||||
snd_pcm_drain(alsa->out_handle);
|
||||
snd_pcm_close(alsa->out_handle);
|
||||
}
|
||||
|
||||
freerdp_dsp_context_free(alsa->dsp_context);
|
||||
free(alsa);
|
||||
}
|
||||
@ -268,21 +236,17 @@ static void tsmf_alsa_free(ITSMFAudioDevice* audio)
|
||||
#define freerdp_tsmf_client_audio_subsystem_entry alsa_freerdp_tsmf_client_audio_subsystem_entry
|
||||
#endif
|
||||
|
||||
ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void)
|
||||
ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void)
|
||||
{
|
||||
TSMFAlsaAudioDevice* alsa;
|
||||
|
||||
alsa = (TSMFAlsaAudioDevice*) malloc(sizeof(TSMFAlsaAudioDevice));
|
||||
TSMFAlsaAudioDevice *alsa;
|
||||
alsa = (TSMFAlsaAudioDevice *) malloc(sizeof(TSMFAlsaAudioDevice));
|
||||
ZeroMemory(alsa, sizeof(TSMFAlsaAudioDevice));
|
||||
|
||||
alsa->iface.Open = tsmf_alsa_open;
|
||||
alsa->iface.SetFormat = tsmf_alsa_set_format;
|
||||
alsa->iface.Play = tsmf_alsa_play;
|
||||
alsa->iface.GetLatency = tsmf_alsa_get_latency;
|
||||
alsa->iface.Flush = tsmf_alsa_flush;
|
||||
alsa->iface.Free = tsmf_alsa_free;
|
||||
|
||||
alsa->dsp_context = freerdp_dsp_context_new();
|
||||
|
||||
return (ITSMFAudioDevice*) alsa;
|
||||
return (ITSMFAudioDevice *) alsa;
|
||||
}
|
||||
|
@ -32,8 +32,6 @@
|
||||
|
||||
#include <libavcodec/avcodec.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
#include "tsmf_constants.h"
|
||||
#include "tsmf_decoder.h"
|
||||
|
||||
@ -59,55 +57,47 @@ typedef struct _TSMFFFmpegDecoder
|
||||
#else
|
||||
enum AVCodecID codec_id;
|
||||
#endif
|
||||
AVCodecContext* codec_context;
|
||||
AVCodec* codec;
|
||||
AVFrame* frame;
|
||||
AVCodecContext *codec_context;
|
||||
AVCodec *codec;
|
||||
AVFrame *frame;
|
||||
int prepared;
|
||||
|
||||
BYTE* decoded_data;
|
||||
BYTE *decoded_data;
|
||||
UINT32 decoded_size;
|
||||
UINT32 decoded_size_max;
|
||||
} TSMFFFmpegDecoder;
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder* decoder)
|
||||
static BOOL tsmf_ffmpeg_init_context(ITSMFDecoder *decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
mdecoder->codec_context = avcodec_alloc_context3(NULL);
|
||||
|
||||
if (!mdecoder->codec_context)
|
||||
if(!mdecoder->codec_context)
|
||||
{
|
||||
DEBUG_WARN("avcodec_alloc_context failed.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type)
|
||||
static BOOL tsmf_ffmpeg_init_video_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
mdecoder->codec_context->width = media_type->Width;
|
||||
mdecoder->codec_context->height = media_type->Height;
|
||||
mdecoder->codec_context->bit_rate = media_type->BitRate;
|
||||
mdecoder->codec_context->time_base.den = media_type->SamplesPerSecond.Numerator;
|
||||
mdecoder->codec_context->time_base.num = media_type->SamplesPerSecond.Denominator;
|
||||
|
||||
mdecoder->frame = avcodec_alloc_frame();
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type)
|
||||
static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
mdecoder->codec_context->sample_rate = media_type->SamplesPerSecond.Numerator;
|
||||
mdecoder->codec_context->bit_rate = media_type->BitRate;
|
||||
mdecoder->codec_context->channels = media_type->Channels;
|
||||
mdecoder->codec_context->block_align = media_type->BlockAlign;
|
||||
|
||||
#if LIBAVCODEC_VERSION_MAJOR < 55
|
||||
#ifdef AV_CPU_FLAG_SSE2
|
||||
mdecoder->codec_context->dsp_mask = AV_CPU_FLAG_SSE2 | AV_CPU_FLAG_MMX2;
|
||||
@ -125,43 +115,38 @@ static BOOL tsmf_ffmpeg_init_audio_stream(ITSMFDecoder* decoder, const TS_AM_MED
|
||||
av_set_cpu_flags_mask(FF_MM_SSE2 | FF_MM_MMX2);
|
||||
#endif
|
||||
#endif /* LIBAVCODEC_VERSION_MAJOR < 55 */
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYPE* media_type)
|
||||
static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder *decoder, const TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
BYTE* p;
|
||||
BYTE *p;
|
||||
UINT32 size;
|
||||
const BYTE* s;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
const BYTE *s;
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
mdecoder->codec = avcodec_find_decoder(mdecoder->codec_id);
|
||||
|
||||
if (!mdecoder->codec)
|
||||
if(!mdecoder->codec)
|
||||
{
|
||||
DEBUG_WARN("avcodec_find_decoder failed.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mdecoder->codec_context->codec_id = mdecoder->codec_id;
|
||||
mdecoder->codec_context->codec_type = mdecoder->media_type;
|
||||
|
||||
if (mdecoder->media_type == AVMEDIA_TYPE_VIDEO)
|
||||
if(mdecoder->media_type == AVMEDIA_TYPE_VIDEO)
|
||||
{
|
||||
if (!tsmf_ffmpeg_init_video_stream(decoder, media_type))
|
||||
if(!tsmf_ffmpeg_init_video_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
}
|
||||
else if (mdecoder->media_type == AVMEDIA_TYPE_AUDIO)
|
||||
else
|
||||
if(mdecoder->media_type == AVMEDIA_TYPE_AUDIO)
|
||||
{
|
||||
if(!tsmf_ffmpeg_init_audio_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
}
|
||||
if(media_type->ExtraData)
|
||||
{
|
||||
if (!tsmf_ffmpeg_init_audio_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (media_type->ExtraData)
|
||||
{
|
||||
if (media_type->SubType == TSMF_SUB_TYPE_AVC1 &&
|
||||
media_type->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO)
|
||||
if(media_type->SubType == TSMF_SUB_TYPE_AVC1 &&
|
||||
media_type->FormatType == TSMF_FORMAT_TYPE_MPEG2VIDEOINFO)
|
||||
{
|
||||
/* The extradata format that FFmpeg uses is following CodecPrivate in Matroska.
|
||||
See http://haali.su/mkv/codecs.pdf */
|
||||
@ -194,33 +179,27 @@ static BOOL tsmf_ffmpeg_init_stream(ITSMFDecoder* decoder, const TS_AM_MEDIA_TYP
|
||||
memset(mdecoder->codec_context->extradata + media_type->ExtraDataSize, 0, 8);
|
||||
}
|
||||
}
|
||||
|
||||
if (mdecoder->codec->capabilities & CODEC_CAP_TRUNCATED)
|
||||
if(mdecoder->codec->capabilities & CODEC_CAP_TRUNCATED)
|
||||
mdecoder->codec_context->flags |= CODEC_FLAG_TRUNCATED;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder* decoder)
|
||||
static BOOL tsmf_ffmpeg_prepare(ITSMFDecoder *decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
if (avcodec_open2(mdecoder->codec_context, mdecoder->codec, NULL) < 0)
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
if(avcodec_open2(mdecoder->codec_context, mdecoder->codec, NULL) < 0)
|
||||
{
|
||||
DEBUG_WARN("avcodec_open2 failed.");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
mdecoder->prepared = 1;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type)
|
||||
static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
switch (media_type->MajorType)
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
switch(media_type->MajorType)
|
||||
{
|
||||
case TSMF_MAJOR_TYPE_VIDEO:
|
||||
mdecoder->media_type = AVMEDIA_TYPE_VIDEO;
|
||||
@ -231,7 +210,7 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* medi
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
switch (media_type->SubType)
|
||||
switch(media_type->SubType)
|
||||
{
|
||||
case TSMF_SUB_TYPE_WVC1:
|
||||
mdecoder->codec_id = CODEC_ID_VC1;
|
||||
@ -259,7 +238,7 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* medi
|
||||
/* For AAC the pFormat is a HEAACWAVEINFO struct, and the codec data
|
||||
is at the end of it. See
|
||||
http://msdn.microsoft.com/en-us/library/dd757806.aspx */
|
||||
if (media_type->ExtraData)
|
||||
if(media_type->ExtraData)
|
||||
{
|
||||
media_type->ExtraData += 12;
|
||||
media_type->ExtraDataSize -= 12;
|
||||
@ -275,118 +254,108 @@ static BOOL tsmf_ffmpeg_set_format(ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* medi
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!tsmf_ffmpeg_init_context(decoder))
|
||||
if(!tsmf_ffmpeg_init_context(decoder))
|
||||
return FALSE;
|
||||
if (!tsmf_ffmpeg_init_stream(decoder, media_type))
|
||||
if(!tsmf_ffmpeg_init_stream(decoder, media_type))
|
||||
return FALSE;
|
||||
if (!tsmf_ffmpeg_prepare(decoder))
|
||||
if(!tsmf_ffmpeg_prepare(decoder))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions)
|
||||
static BOOL tsmf_ffmpeg_decode_video(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
int decoded;
|
||||
int len;
|
||||
AVFrame* frame;
|
||||
AVFrame *frame;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
#if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20)
|
||||
len = avcodec_decode_video(mdecoder->codec_context, mdecoder->frame, &decoded, data, data_size);
|
||||
#else
|
||||
{
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = (BYTE*) data;
|
||||
pkt.data = (BYTE *) data;
|
||||
pkt.size = data_size;
|
||||
if (extensions & TSMM_SAMPLE_EXT_CLEANPOINT)
|
||||
if(extensions & TSMM_SAMPLE_EXT_CLEANPOINT)
|
||||
pkt.flags |= AV_PKT_FLAG_KEY;
|
||||
len = avcodec_decode_video2(mdecoder->codec_context, mdecoder->frame, &decoded, &pkt);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (len < 0)
|
||||
if(len < 0)
|
||||
{
|
||||
DEBUG_WARN("data_size %d, avcodec_decode_video failed (%d)", data_size, len);
|
||||
ret = FALSE;
|
||||
}
|
||||
else if (!decoded)
|
||||
{
|
||||
DEBUG_WARN("data_size %d, no frame is decoded.", data_size);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_DVC("linesize[0] %d linesize[1] %d linesize[2] %d linesize[3] %d "
|
||||
"pix_fmt %d width %d height %d",
|
||||
mdecoder->frame->linesize[0], mdecoder->frame->linesize[1],
|
||||
mdecoder->frame->linesize[2], mdecoder->frame->linesize[3],
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
|
||||
mdecoder->decoded_size = avpicture_get_size(mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
mdecoder->decoded_data = malloc(mdecoder->decoded_size);
|
||||
ZeroMemory(mdecoder->decoded_data, mdecoder->decoded_size);
|
||||
frame = avcodec_alloc_frame();
|
||||
avpicture_fill((AVPicture*) frame, mdecoder->decoded_data,
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
|
||||
av_picture_copy((AVPicture*) frame, (AVPicture*) mdecoder->frame,
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
|
||||
av_free(frame);
|
||||
}
|
||||
|
||||
if(!decoded)
|
||||
{
|
||||
DEBUG_WARN("data_size %d, no frame is decoded.", data_size);
|
||||
ret = FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
DEBUG_TSMF("linesize[0] %d linesize[1] %d linesize[2] %d linesize[3] %d "
|
||||
"pix_fmt %d width %d height %d",
|
||||
mdecoder->frame->linesize[0], mdecoder->frame->linesize[1],
|
||||
mdecoder->frame->linesize[2], mdecoder->frame->linesize[3],
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
mdecoder->decoded_size = avpicture_get_size(mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
mdecoder->decoded_data = malloc(mdecoder->decoded_size);
|
||||
ZeroMemory(mdecoder->decoded_data, mdecoder->decoded_size);
|
||||
frame = avcodec_alloc_frame();
|
||||
avpicture_fill((AVPicture *) frame, mdecoder->decoded_data,
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
av_picture_copy((AVPicture *) frame, (AVPicture *) mdecoder->frame,
|
||||
mdecoder->codec_context->pix_fmt,
|
||||
mdecoder->codec_context->width, mdecoder->codec_context->height);
|
||||
av_free(frame);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions)
|
||||
static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
int len;
|
||||
int frame_size;
|
||||
UINT32 src_size;
|
||||
const BYTE* src;
|
||||
BYTE* dst;
|
||||
const BYTE *src;
|
||||
BYTE *dst;
|
||||
int dst_offset;
|
||||
|
||||
#if 0
|
||||
LLOGLN(0, ("tsmf_ffmpeg_decode_audio: data_size %d", data_size));
|
||||
int i;
|
||||
for (i = 0; i < data_size; i++)
|
||||
for(i = 0; i < data_size; i++)
|
||||
{
|
||||
LLOG(0, ("%02X ", data[i]));
|
||||
if (i % 16 == 15)
|
||||
if(i % 16 == 15)
|
||||
LLOG(0, ("\n"));
|
||||
}
|
||||
LLOG(0, ("\n"));
|
||||
#endif
|
||||
|
||||
if (mdecoder->decoded_size_max == 0)
|
||||
if(mdecoder->decoded_size_max == 0)
|
||||
mdecoder->decoded_size_max = MAX_AUDIO_FRAME_SIZE + 16;
|
||||
mdecoder->decoded_data = malloc(mdecoder->decoded_size_max);
|
||||
ZeroMemory(mdecoder->decoded_data, mdecoder->decoded_size_max);
|
||||
/* align the memory for SSE2 needs */
|
||||
dst = (BYTE*) (((uintptr_t) mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
dst = (BYTE *)(((uintptr_t) mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
dst_offset = dst - mdecoder->decoded_data;
|
||||
src = data;
|
||||
src_size = data_size;
|
||||
|
||||
while (src_size > 0)
|
||||
while(src_size > 0)
|
||||
{
|
||||
/* Ensure enough space for decoding */
|
||||
if (mdecoder->decoded_size_max - mdecoder->decoded_size < MAX_AUDIO_FRAME_SIZE)
|
||||
if(mdecoder->decoded_size_max - mdecoder->decoded_size < MAX_AUDIO_FRAME_SIZE)
|
||||
{
|
||||
mdecoder->decoded_size_max = mdecoder->decoded_size_max * 2 + 16;
|
||||
mdecoder->decoded_data = realloc(mdecoder->decoded_data, mdecoder->decoded_size_max);
|
||||
dst = (BYTE*) (((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
if (dst - mdecoder->decoded_data != dst_offset)
|
||||
dst = (BYTE *)(((uintptr_t)mdecoder->decoded_data + 15) & ~ 0x0F);
|
||||
if(dst - mdecoder->decoded_data != dst_offset)
|
||||
{
|
||||
/* re-align the memory if the alignment has changed after realloc */
|
||||
memmove(dst, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
|
||||
@ -394,72 +363,64 @@ static BOOL tsmf_ffmpeg_decode_audio(ITSMFDecoder* decoder, const BYTE* data, UI
|
||||
}
|
||||
dst += mdecoder->decoded_size;
|
||||
}
|
||||
|
||||
frame_size = mdecoder->decoded_size_max - mdecoder->decoded_size;
|
||||
#if LIBAVCODEC_VERSION_MAJOR < 52 || (LIBAVCODEC_VERSION_MAJOR == 52 && LIBAVCODEC_VERSION_MINOR <= 20)
|
||||
len = avcodec_decode_audio2(mdecoder->codec_context,
|
||||
(int16_t*) dst, &frame_size, src, src_size);
|
||||
(int16_t *) dst, &frame_size, src, src_size);
|
||||
#else
|
||||
{
|
||||
AVFrame* decoded_frame = avcodec_alloc_frame();
|
||||
AVFrame *decoded_frame = avcodec_alloc_frame();
|
||||
int got_frame = 0;
|
||||
AVPacket pkt;
|
||||
av_init_packet(&pkt);
|
||||
pkt.data = (BYTE*) src;
|
||||
pkt.data = (BYTE *) src;
|
||||
pkt.size = src_size;
|
||||
len = avcodec_decode_audio4(mdecoder->codec_context, decoded_frame, &got_frame, &pkt);
|
||||
|
||||
if (len >= 0 && got_frame)
|
||||
if(len >= 0 && got_frame)
|
||||
{
|
||||
frame_size = av_samples_get_buffer_size(NULL, mdecoder->codec_context->channels,
|
||||
decoded_frame->nb_samples, mdecoder->codec_context->sample_fmt, 1);
|
||||
decoded_frame->nb_samples, mdecoder->codec_context->sample_fmt, 1);
|
||||
memcpy(dst, decoded_frame->data[0], frame_size);
|
||||
}
|
||||
|
||||
av_free(decoded_frame);
|
||||
}
|
||||
#endif
|
||||
if (len <= 0 || frame_size <= 0)
|
||||
if(len <= 0 || frame_size <= 0)
|
||||
{
|
||||
DEBUG_WARN("error decoding");
|
||||
break;
|
||||
}
|
||||
|
||||
src += len;
|
||||
src_size -= len;
|
||||
mdecoder->decoded_size += frame_size;
|
||||
dst += frame_size;
|
||||
}
|
||||
|
||||
if (mdecoder->decoded_size == 0)
|
||||
if(mdecoder->decoded_size == 0)
|
||||
{
|
||||
free(mdecoder->decoded_data);
|
||||
mdecoder->decoded_data = NULL;
|
||||
}
|
||||
else if (dst_offset)
|
||||
{
|
||||
/* move the aligned decoded data to original place */
|
||||
memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
|
||||
}
|
||||
|
||||
DEBUG_DVC("data_size %d decoded_size %d",
|
||||
data_size, mdecoder->decoded_size);
|
||||
|
||||
else
|
||||
if(dst_offset)
|
||||
{
|
||||
/* move the aligned decoded data to original place */
|
||||
memmove(mdecoder->decoded_data, mdecoder->decoded_data + dst_offset, mdecoder->decoded_size);
|
||||
}
|
||||
DEBUG_TSMF("data_size %d decoded_size %d",
|
||||
data_size, mdecoder->decoded_size);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_decode(ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions)
|
||||
static BOOL tsmf_ffmpeg_decode(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
if (mdecoder->decoded_data)
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
if(mdecoder->decoded_data)
|
||||
{
|
||||
free(mdecoder->decoded_data);
|
||||
mdecoder->decoded_data = NULL;
|
||||
}
|
||||
mdecoder->decoded_size = 0;
|
||||
|
||||
switch (mdecoder->media_type)
|
||||
switch(mdecoder->media_type)
|
||||
{
|
||||
case AVMEDIA_TYPE_VIDEO:
|
||||
return tsmf_ffmpeg_decode_video(decoder, data, data_size, extensions);
|
||||
@ -471,40 +432,35 @@ static BOOL tsmf_ffmpeg_decode(ITSMFDecoder* decoder, const BYTE* data, UINT32 d
|
||||
}
|
||||
}
|
||||
|
||||
static BYTE* tsmf_ffmpeg_get_decoded_data(ITSMFDecoder* decoder, UINT32* size)
|
||||
static BYTE *tsmf_ffmpeg_get_decoded_data(ITSMFDecoder *decoder, UINT32 *size)
|
||||
{
|
||||
BYTE* buf;
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
BYTE *buf;
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
*size = mdecoder->decoded_size;
|
||||
buf = mdecoder->decoded_data;
|
||||
mdecoder->decoded_data = NULL;
|
||||
mdecoder->decoded_size = 0;
|
||||
|
||||
return buf;
|
||||
}
|
||||
|
||||
static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder* decoder)
|
||||
static UINT32 tsmf_ffmpeg_get_decoded_format(ITSMFDecoder *decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
switch (mdecoder->codec_context->pix_fmt)
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
switch(mdecoder->codec_context->pix_fmt)
|
||||
{
|
||||
case PIX_FMT_YUV420P:
|
||||
return RDP_PIXFMT_I420;
|
||||
|
||||
default:
|
||||
DEBUG_WARN("unsupported pixel format %u",
|
||||
mdecoder->codec_context->pix_fmt);
|
||||
mdecoder->codec_context->pix_fmt);
|
||||
return (UINT32) -1;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder* decoder, UINT32* width, UINT32* height)
|
||||
static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder *decoder, UINT32 *width, UINT32 *height)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
if (mdecoder->codec_context->width > 0 && mdecoder->codec_context->height > 0)
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
if(mdecoder->codec_context->width > 0 && mdecoder->codec_context->height > 0)
|
||||
{
|
||||
*width = mdecoder->codec_context->width;
|
||||
*height = mdecoder->codec_context->height;
|
||||
@ -516,25 +472,21 @@ static BOOL tsmf_ffmpeg_get_decoded_dimension(ITSMFDecoder* decoder, UINT32* wid
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_ffmpeg_free(ITSMFDecoder* decoder)
|
||||
static void tsmf_ffmpeg_free(ITSMFDecoder *decoder)
|
||||
{
|
||||
TSMFFFmpegDecoder* mdecoder = (TSMFFFmpegDecoder*) decoder;
|
||||
|
||||
if (mdecoder->frame)
|
||||
TSMFFFmpegDecoder *mdecoder = (TSMFFFmpegDecoder *) decoder;
|
||||
if(mdecoder->frame)
|
||||
av_free(mdecoder->frame);
|
||||
|
||||
if (mdecoder->decoded_data)
|
||||
if(mdecoder->decoded_data)
|
||||
free(mdecoder->decoded_data);
|
||||
|
||||
if (mdecoder->codec_context)
|
||||
if(mdecoder->codec_context)
|
||||
{
|
||||
if (mdecoder->prepared)
|
||||
if(mdecoder->prepared)
|
||||
avcodec_close(mdecoder->codec_context);
|
||||
if (mdecoder->codec_context->extradata)
|
||||
if(mdecoder->codec_context->extradata)
|
||||
free(mdecoder->codec_context->extradata);
|
||||
av_free(mdecoder->codec_context);
|
||||
}
|
||||
|
||||
free(decoder);
|
||||
}
|
||||
|
||||
@ -544,27 +496,22 @@ static BOOL initialized = FALSE;
|
||||
#define freerdp_tsmf_client_decoder_subsystem_entry ffmpeg_freerdp_tsmf_client_decoder_subsystem_entry
|
||||
#endif
|
||||
|
||||
ITSMFDecoder* freerdp_tsmf_client_decoder_subsystem_entry(void)
|
||||
ITSMFDecoder *freerdp_tsmf_client_decoder_subsystem_entry(void)
|
||||
{
|
||||
TSMFFFmpegDecoder* decoder;
|
||||
|
||||
if (!initialized)
|
||||
TSMFFFmpegDecoder *decoder;
|
||||
if(!initialized)
|
||||
{
|
||||
avcodec_register_all();
|
||||
initialized = TRUE;
|
||||
}
|
||||
|
||||
fprintf(stderr, "TSMFDecoderEntry FFMPEG\n");
|
||||
|
||||
decoder = (TSMFFFmpegDecoder*) malloc(sizeof(TSMFFFmpegDecoder));
|
||||
decoder = (TSMFFFmpegDecoder *) malloc(sizeof(TSMFFFmpegDecoder));
|
||||
ZeroMemory(decoder, sizeof(TSMFFFmpegDecoder));
|
||||
|
||||
decoder->iface.SetFormat = tsmf_ffmpeg_set_format;
|
||||
decoder->iface.Decode = tsmf_ffmpeg_decode;
|
||||
decoder->iface.GetDecodedData = tsmf_ffmpeg_get_decoded_data;
|
||||
decoder->iface.GetDecodedFormat = tsmf_ffmpeg_get_decoded_format;
|
||||
decoder->iface.GetDecodedDimension = tsmf_ffmpeg_get_decoded_dimension;
|
||||
decoder->iface.Free = tsmf_ffmpeg_free;
|
||||
|
||||
return (ITSMFDecoder*) decoder;
|
||||
return (ITSMFDecoder *) decoder;
|
||||
}
|
||||
|
@ -7,7 +7,7 @@
|
||||
# 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
|
||||
# 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,
|
||||
@ -17,26 +17,60 @@
|
||||
|
||||
define_channel_client_subsystem("tsmf" "gstreamer" "decoder")
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
tsmf_gstreamer.c)
|
||||
if(NOT GSTREAMER_0_10_FOUND AND NOT GSTREAMER_1_0_FOUND)
|
||||
message(FATAL_ERROR "GStreamer library not found, but required for TSMF module.")
|
||||
elseif (GSTREAMER_0_10_FOUND AND GSTREAMER_1_0_FOUND)
|
||||
message(FATAL_ERROR "GStreamer 0.10 and GStreamer 1.0 support are mutually exclusive!")
|
||||
endif()
|
||||
|
||||
set(SRC "tsmf_gstreamer.c")
|
||||
|
||||
if (GSTREAMER_1_0_FOUND)
|
||||
set(LIBS ${GSTREAMER_1_0_LIBRARIES})
|
||||
include_directories(${GSTREAMER_1_0_INCLUDE_DIRS})
|
||||
elseif (GSTREAMER_0_10_FOUND)
|
||||
set(LIBS ${GSTREAMER_0_10_LIBRARIES})
|
||||
include_directories(${GSTREAMER_0_10_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if(ANDROID)
|
||||
set(SRC ${SRC}
|
||||
tsmf_android.c)
|
||||
set(LIBS ${LIBS})
|
||||
else()
|
||||
set(XEXT_FEATURE_TYPE "RECOMMENDED")
|
||||
set(XEXT_FEATURE_PURPOSE "X11 extension")
|
||||
set(XEXT_FEATURE_DESCRIPTION "X11 core extensions")
|
||||
|
||||
find_feature(Xext ${XEXT_FEATURE_TYPE} ${XEXT_FEATURE_PURPOSE} ${XEXT_FEATURE_DESCRIPTION})
|
||||
|
||||
set(SRC ${SRC}
|
||||
tsmf_X11.c)
|
||||
set(LIBS ${LIBS} ${X11_LIBRARIES} ${XEXT_LIBRARIES})
|
||||
|
||||
if(NOT XEXT_FOUND)
|
||||
message(FATAL_ERROR "Xext library not found, but required for TSMF module.")
|
||||
else()
|
||||
add_definitions(-DWITH_XEXT=1)
|
||||
endif()
|
||||
|
||||
endif()
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS "${SRC}")
|
||||
|
||||
include_directories(..)
|
||||
include_directories(${GSTREAMER_INCLUDE_DIRS})
|
||||
|
||||
add_channel_client_subsystem_library(${MODULE_PREFIX} ${MODULE_NAME} ${CHANNEL_NAME} "" TRUE "")
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES PREFIX "")
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE freerdp
|
||||
MODULES freerdp-utils)
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE freerdp
|
||||
MODULES freerdp-utils)
|
||||
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS}
|
||||
${GSTREAMER_LIBRARIES}
|
||||
gstapp-0.10
|
||||
gstinterfaces-0.10
|
||||
Xrandr X11 Xext)
|
||||
${LIBS})
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
|
316
channels/tsmf/client/gstreamer/tsmf_X11.c
Normal file
316
channels/tsmf/client/gstreamer/tsmf_X11.c
Normal file
@ -0,0 +1,316 @@
|
||||
/*
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Video Redirection Virtual Channel - GStreamer Decoder X11 specifics
|
||||
*
|
||||
* (C) Copyright 2014 Thincast Technologies GmbH
|
||||
* (C) Copyright 2014 Armin Novak <armin.novak@thincast.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 <assert.h>
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syscall.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <winpr/thread.h>
|
||||
|
||||
#include <gst/gst.h>
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
#include <gst/video/videooverlay.h>
|
||||
#else
|
||||
#include <gst/interfaces/xoverlay.h>
|
||||
#endif
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/Xrandr.h>
|
||||
#include <X11/extensions/shape.h>
|
||||
|
||||
#include <freerdp/channels/tsmf.h>
|
||||
|
||||
#include "tsmf_platform.h"
|
||||
#include "tsmf_constants.h"
|
||||
#include "tsmf_decoder.h"
|
||||
|
||||
#if !defined(WITH_XEXT)
|
||||
#warning "Building TSMF without shape extension support"
|
||||
#endif
|
||||
|
||||
struct X11Handle
|
||||
{
|
||||
int shmid;
|
||||
int *xfwin;
|
||||
#if defined(WITH_XEXT)
|
||||
BOOL has_shape;
|
||||
#endif
|
||||
Display *disp;
|
||||
Window subwin;
|
||||
};
|
||||
|
||||
static const char *get_shm_id()
|
||||
{
|
||||
static char shm_id[64];
|
||||
snprintf(shm_id, sizeof(shm_id), "com.freerdp.xfreerpd.tsmf_%016X", GetCurrentProcessId());
|
||||
return shm_id;
|
||||
}
|
||||
|
||||
const char *tsmf_platform_get_video_sink(void)
|
||||
{
|
||||
return "xvimagesink";
|
||||
}
|
||||
|
||||
const char *tsmf_platform_get_audio_sink(void)
|
||||
{
|
||||
return "autoaudiosink";
|
||||
}
|
||||
|
||||
int tsmf_platform_create(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
struct X11Handle *hdl;
|
||||
assert(decoder);
|
||||
assert(!decoder->platform);
|
||||
hdl = malloc(sizeof(struct X11Handle));
|
||||
|
||||
if (!hdl)
|
||||
{
|
||||
DEBUG_WARN("%s: Could not allocate handle.", __func__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(hdl, 0, sizeof(struct X11Handle));
|
||||
decoder->platform = hdl;
|
||||
hdl->shmid = shm_open(get_shm_id(), O_RDWR, PROT_READ | PROT_WRITE);;
|
||||
|
||||
if (hdl->shmid < 0)
|
||||
{
|
||||
DEBUG_WARN("%s: failed to get access to shared memory - shmget()",
|
||||
__func__);
|
||||
return -2;
|
||||
}
|
||||
else
|
||||
hdl->xfwin = mmap(0, sizeof(void *), PROT_READ | PROT_WRITE, MAP_SHARED, hdl->shmid, 0);
|
||||
|
||||
if (hdl->xfwin == (int *)-1)
|
||||
{
|
||||
DEBUG_WARN("%s: shmat failed!", __func__);
|
||||
return -3;
|
||||
}
|
||||
|
||||
hdl->disp = XOpenDisplay(NULL);
|
||||
|
||||
if (!hdl->disp)
|
||||
{
|
||||
DEBUG_WARN("Failed to open display");
|
||||
return -4;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_platform_set_format(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
|
||||
if (decoder->media_type == TSMF_MAJOR_TYPE_VIDEO)
|
||||
{
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
assert(decoder->pipe);
|
||||
GstBus *bus = gst_pipeline_get_bus(GST_PIPELINE(decoder->pipe));
|
||||
|
||||
if (!bus)
|
||||
{
|
||||
DEBUG_WARN("gst_pipeline_get_bus failed!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_platform_free(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
struct X11Handle *hdl = decoder->platform;
|
||||
|
||||
if (!hdl)
|
||||
return -1;
|
||||
|
||||
if (hdl->disp)
|
||||
XCloseDisplay(hdl->disp);
|
||||
|
||||
if (hdl->xfwin)
|
||||
munmap(0, sizeof(void *));
|
||||
|
||||
if (hdl->shmid >= 0)
|
||||
close(hdl->shmid);
|
||||
|
||||
free(hdl);
|
||||
decoder->platform = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_window_create(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO)
|
||||
{
|
||||
decoder->ready = TRUE;
|
||||
return -3;
|
||||
}
|
||||
else
|
||||
{
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(decoder->outsink);
|
||||
#else
|
||||
GstXOverlay *overlay = GST_X_OVERLAY(decoder->outsink);
|
||||
#endif
|
||||
struct X11Handle *hdl = (struct X11Handle *)decoder->platform;
|
||||
assert(decoder);
|
||||
assert(hdl);
|
||||
|
||||
if (!hdl->subwin)
|
||||
{
|
||||
int event, error;
|
||||
hdl->subwin = XCreateSimpleWindow(hdl->disp, *(int *)hdl->xfwin, 0, 0, 1, 1, 0, 0, 0);
|
||||
|
||||
if (!hdl->subwin)
|
||||
{
|
||||
DEBUG_WARN("Could not create subwindow!");
|
||||
}
|
||||
|
||||
XMapWindow(hdl->disp, hdl->subwin);
|
||||
XSync(hdl->disp, FALSE);
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
gst_video_overlay_set_window_handle(overlay, hdl->subwin);
|
||||
#else
|
||||
gst_x_overlay_set_window_handle(overlay, hdl->subwin);
|
||||
#endif
|
||||
decoder->ready = TRUE;
|
||||
#if defined(WITH_XEXT)
|
||||
hdl->has_shape = XShapeQueryExtension(hdl->disp, &event, &error);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
gst_video_overlay_handle_events(overlay, TRUE);
|
||||
#else
|
||||
gst_x_overlay_handle_events(overlay, TRUE);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y, int width,
|
||||
int height, int nr_rects, RDP_RECT *rects)
|
||||
{
|
||||
if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO)
|
||||
return -3;
|
||||
else
|
||||
{
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
GstVideoOverlay *overlay = GST_VIDEO_OVERLAY(decoder->outsink);
|
||||
#else
|
||||
GstXOverlay *overlay = GST_X_OVERLAY(decoder->outsink);
|
||||
#endif
|
||||
struct X11Handle *hdl = (struct X11Handle *)decoder->platform;
|
||||
DEBUG_TSMF("resize: x=%d, y=%d, w=%d, h=%d", x, y, width, height);
|
||||
assert(decoder);
|
||||
assert(hdl);
|
||||
#if GST_VERSION_MAJOR > 0
|
||||
|
||||
if (!gst_video_overlay_set_render_rectangle(overlay, 0, 0, width, height))
|
||||
{
|
||||
DEBUG_WARN("Could not resize overlay!");
|
||||
}
|
||||
|
||||
gst_video_overlay_expose(overlay);
|
||||
#else
|
||||
if (!gst_x_overlay_set_render_rectangle(overlay, 0, 0, width, height))
|
||||
{
|
||||
DEBUG_WARN("Could not resize overlay!");
|
||||
}
|
||||
|
||||
gst_x_overlay_expose(overlay);
|
||||
#endif
|
||||
|
||||
if (hdl->subwin)
|
||||
{
|
||||
XMoveResizeWindow(hdl->disp, hdl->subwin, x, y, width, height);
|
||||
#if defined(WITH_XEXT)
|
||||
|
||||
if (hdl->has_shape)
|
||||
{
|
||||
int i;
|
||||
XRectangle *xrects = calloc(nr_rects, sizeof(XRectangle));
|
||||
|
||||
for (i=0; i<nr_rects; i++)
|
||||
{
|
||||
xrects[i].x = rects[i].x - x;
|
||||
xrects[i].y = rects[i].y - y;
|
||||
xrects[i].width = rects[i].width;
|
||||
xrects[i].height = rects[i].height;
|
||||
}
|
||||
|
||||
XShapeCombineRectangles(hdl->disp, hdl->subwin, ShapeBounding, x, y, xrects, nr_rects, ShapeSet, 0);
|
||||
free(xrects);
|
||||
}
|
||||
|
||||
#endif
|
||||
XSync(hdl->disp, FALSE);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int tsmf_window_pause(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_window_resume(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
assert(decoder);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_window_destroy(TSMFGstreamerDecoder *decoder)
|
||||
{
|
||||
struct X11Handle *hdl = (struct X11Handle *)decoder->platform;
|
||||
decoder->ready = FALSE;
|
||||
|
||||
if (decoder->media_type != TSMF_MAJOR_TYPE_VIDEO)
|
||||
return -3;
|
||||
|
||||
assert(decoder);
|
||||
assert(hdl);
|
||||
|
||||
if (hdl->subwin)
|
||||
{
|
||||
XDestroyWindow(hdl->disp, hdl->subwin);
|
||||
XSync(hdl->disp, FALSE);
|
||||
}
|
||||
|
||||
hdl->subwin = 0;
|
||||
return 0;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
83
channels/tsmf/client/gstreamer/tsmf_platform.h
Normal file
83
channels/tsmf/client/gstreamer/tsmf_platform.h
Normal file
@ -0,0 +1,83 @@
|
||||
/*
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Video Redirection Virtual Channel - GStreamer Decoder
|
||||
* platform specific functions
|
||||
*
|
||||
* (C) Copyright 2014 Thincast Technologies GmbH
|
||||
* (C) Copyright 2014 Armin Novak <armin.novak@thincast.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 _TSMF_PLATFORM_H_
|
||||
#define _TSMF_PLATFORM_H_
|
||||
|
||||
#include <gst/gst.h>
|
||||
#include <tsmf_decoder.h>
|
||||
|
||||
typedef struct _TSMFGstreamerDecoder
|
||||
{
|
||||
ITSMFDecoder iface;
|
||||
|
||||
int media_type; /* TSMF_MAJOR_TYPE_AUDIO or TSMF_MAJOR_TYPE_VIDEO */
|
||||
|
||||
gint64 duration;
|
||||
|
||||
GstState state;
|
||||
GstCaps *gst_caps;
|
||||
|
||||
GstElement *pipe;
|
||||
GstElement *src;
|
||||
GstElement *outsink;
|
||||
GstElement *volume;
|
||||
|
||||
BOOL ready;
|
||||
BOOL paused;
|
||||
UINT64 last_sample_end_time;
|
||||
|
||||
double gstVolume;
|
||||
BOOL gstMuted;
|
||||
|
||||
int pipeline_start_time_valid; /* We've set the start time and have not reset the pipeline */
|
||||
int shutdown; /* The decoder stream is shutting down */
|
||||
|
||||
void *platform;
|
||||
|
||||
BOOL (*ack_cb)(void *,BOOL);
|
||||
void (*sync_cb)(void *);
|
||||
void *stream;
|
||||
|
||||
} TSMFGstreamerDecoder;
|
||||
|
||||
const char *get_type(TSMFGstreamerDecoder *mdecoder);
|
||||
|
||||
const char *tsmf_platform_get_video_sink(void);
|
||||
const char *tsmf_platform_get_audio_sink(void);
|
||||
|
||||
int tsmf_platform_create(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_platform_set_format(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_platform_register_handler(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_platform_free(TSMFGstreamerDecoder *decoder);
|
||||
|
||||
int tsmf_window_create(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_window_resize(TSMFGstreamerDecoder *decoder, int x, int y,
|
||||
int width, int height, int nr_rect, RDP_RECT *visible);
|
||||
int tsmf_window_destroy(TSMFGstreamerDecoder *decoder);
|
||||
|
||||
int tsmf_window_pause(TSMFGstreamerDecoder *decoder);
|
||||
int tsmf_window_resume(TSMFGstreamerDecoder *decoder);
|
||||
|
||||
BOOL tsmf_gstreamer_add_pad(TSMFGstreamerDecoder *mdecoder);
|
||||
void tsmf_gstreamer_remove_pad(TSMFGstreamerDecoder *mdecoder);
|
||||
|
||||
#endif
|
@ -37,75 +37,70 @@ typedef struct _TSMFPulseAudioDevice
|
||||
ITSMFAudioDevice iface;
|
||||
|
||||
char device[32];
|
||||
pa_threaded_mainloop* mainloop;
|
||||
pa_context* context;
|
||||
pa_threaded_mainloop *mainloop;
|
||||
pa_context *context;
|
||||
pa_sample_spec sample_spec;
|
||||
pa_stream* stream;
|
||||
pa_stream *stream;
|
||||
} TSMFPulseAudioDevice;
|
||||
|
||||
static void tsmf_pulse_context_state_callback(pa_context* context, void* userdata)
|
||||
static void tsmf_pulse_context_state_callback(pa_context *context, void *userdata)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata;
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata;
|
||||
pa_context_state_t state;
|
||||
|
||||
state = pa_context_get_state(context);
|
||||
switch (state)
|
||||
switch(state)
|
||||
{
|
||||
case PA_CONTEXT_READY:
|
||||
DEBUG_DVC("PA_CONTEXT_READY");
|
||||
DEBUG_TSMF("PA_CONTEXT_READY");
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
break;
|
||||
|
||||
case PA_CONTEXT_FAILED:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
DEBUG_DVC("state %d", (int)state);
|
||||
DEBUG_TSMF("state %d", (int)state);
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_DVC("state %d", (int)state);
|
||||
DEBUG_TSMF("state %d", (int)state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse)
|
||||
static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice *pulse)
|
||||
{
|
||||
pa_context_state_t state;
|
||||
|
||||
if (!pulse->context)
|
||||
if(!pulse->context)
|
||||
return FALSE;
|
||||
|
||||
if (pa_context_connect(pulse->context, NULL, 0, NULL))
|
||||
if(pa_context_connect(pulse->context, NULL, 0, NULL))
|
||||
{
|
||||
DEBUG_WARN("pa_context_connect failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
pa_context_errno(pulse->context));
|
||||
return FALSE;
|
||||
}
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
if (pa_threaded_mainloop_start(pulse->mainloop) < 0)
|
||||
if(pa_threaded_mainloop_start(pulse->mainloop) < 0)
|
||||
{
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
DEBUG_WARN("pa_threaded_mainloop_start failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
pa_context_errno(pulse->context));
|
||||
return FALSE;
|
||||
}
|
||||
for (;;)
|
||||
for(;;)
|
||||
{
|
||||
state = pa_context_get_state(pulse->context);
|
||||
if (state == PA_CONTEXT_READY)
|
||||
if(state == PA_CONTEXT_READY)
|
||||
break;
|
||||
if (!PA_CONTEXT_IS_GOOD(state))
|
||||
if(!PA_CONTEXT_IS_GOOD(state))
|
||||
{
|
||||
DEBUG_DVC("bad context state (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
DEBUG_TSMF("bad context state (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
break;
|
||||
}
|
||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
||||
}
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
if (state == PA_CONTEXT_READY)
|
||||
if(state == PA_CONTEXT_READY)
|
||||
{
|
||||
DEBUG_DVC("connected");
|
||||
DEBUG_TSMF("connected");
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
@ -115,166 +110,150 @@ static BOOL tsmf_pulse_connect(TSMFPulseAudioDevice* pulse)
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL tsmf_pulse_open(ITSMFAudioDevice* audio, const char* device)
|
||||
static BOOL tsmf_pulse_open(ITSMFAudioDevice *audio, const char *device)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
|
||||
|
||||
if (device)
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
if(device)
|
||||
{
|
||||
strcpy(pulse->device, device);
|
||||
}
|
||||
|
||||
pulse->mainloop = pa_threaded_mainloop_new();
|
||||
if (!pulse->mainloop)
|
||||
if(!pulse->mainloop)
|
||||
{
|
||||
DEBUG_WARN("pa_threaded_mainloop_new failed");
|
||||
return FALSE;
|
||||
}
|
||||
pulse->context = pa_context_new(pa_threaded_mainloop_get_api(pulse->mainloop), "freerdp");
|
||||
if (!pulse->context)
|
||||
if(!pulse->context)
|
||||
{
|
||||
DEBUG_WARN("pa_context_new failed");
|
||||
return FALSE;
|
||||
}
|
||||
pa_context_set_state_callback(pulse->context, tsmf_pulse_context_state_callback, pulse);
|
||||
if (tsmf_pulse_connect(pulse))
|
||||
if(tsmf_pulse_connect(pulse))
|
||||
{
|
||||
DEBUG_WARN("tsmf_pulse_connect failed");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
DEBUG_DVC("open device %s", pulse->device);
|
||||
DEBUG_TSMF("open device %s", pulse->device);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void tsmf_pulse_stream_success_callback(pa_stream* stream, int success, void* userdata)
|
||||
static void tsmf_pulse_stream_success_callback(pa_stream *stream, int success, void *userdata)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata;
|
||||
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata;
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
}
|
||||
|
||||
static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice* pulse, pa_operation* operation)
|
||||
static void tsmf_pulse_wait_for_operation(TSMFPulseAudioDevice *pulse, pa_operation *operation)
|
||||
{
|
||||
if (operation == NULL)
|
||||
if(operation == NULL)
|
||||
return;
|
||||
while (pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
|
||||
while(pa_operation_get_state(operation) == PA_OPERATION_RUNNING)
|
||||
{
|
||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
||||
}
|
||||
pa_operation_unref(operation);
|
||||
}
|
||||
|
||||
static void tsmf_pulse_stream_state_callback(pa_stream* stream, void* userdata)
|
||||
static void tsmf_pulse_stream_state_callback(pa_stream *stream, void *userdata)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata;
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata;
|
||||
pa_stream_state_t state;
|
||||
|
||||
state = pa_stream_get_state(stream);
|
||||
switch (state)
|
||||
switch(state)
|
||||
{
|
||||
case PA_STREAM_READY:
|
||||
DEBUG_DVC("PA_STREAM_READY");
|
||||
pa_threaded_mainloop_signal (pulse->mainloop, 0);
|
||||
DEBUG_TSMF("PA_STREAM_READY");
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
break;
|
||||
|
||||
case PA_STREAM_FAILED:
|
||||
case PA_STREAM_TERMINATED:
|
||||
DEBUG_DVC("state %d", (int)state);
|
||||
pa_threaded_mainloop_signal (pulse->mainloop, 0);
|
||||
DEBUG_TSMF("state %d", (int)state);
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
break;
|
||||
|
||||
default:
|
||||
DEBUG_DVC("state %d", (int)state);
|
||||
DEBUG_TSMF("state %d", (int)state);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void tsmf_pulse_stream_request_callback(pa_stream* stream, size_t length, void* userdata)
|
||||
static void tsmf_pulse_stream_request_callback(pa_stream *stream, size_t length, void *userdata)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) userdata;
|
||||
|
||||
DEBUG_DVC("%d", (int) length);
|
||||
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) userdata;
|
||||
DEBUG_TSMF("%d", (int) length);
|
||||
pa_threaded_mainloop_signal(pulse->mainloop, 0);
|
||||
}
|
||||
|
||||
static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice* pulse)
|
||||
static BOOL tsmf_pulse_close_stream(TSMFPulseAudioDevice *pulse)
|
||||
{
|
||||
if (!pulse->context || !pulse->stream)
|
||||
if(!pulse->context || !pulse->stream)
|
||||
return FALSE;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
DEBUG_TSMF("");
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
pa_stream_set_write_callback(pulse->stream, NULL, NULL);
|
||||
tsmf_pulse_wait_for_operation(pulse,
|
||||
pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse));
|
||||
pa_stream_drain(pulse->stream, tsmf_pulse_stream_success_callback, pulse));
|
||||
pa_stream_disconnect(pulse->stream);
|
||||
pa_stream_unref(pulse->stream);
|
||||
pulse->stream = NULL;
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse)
|
||||
static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice *pulse)
|
||||
{
|
||||
pa_stream_state_t state;
|
||||
pa_buffer_attr buffer_attr = { 0 };
|
||||
|
||||
if (!pulse->context)
|
||||
if(!pulse->context)
|
||||
return FALSE;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
DEBUG_TSMF("");
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
pulse->stream = pa_stream_new(pulse->context, "freerdp",
|
||||
&pulse->sample_spec, NULL);
|
||||
if (!pulse->stream)
|
||||
&pulse->sample_spec, NULL);
|
||||
if(!pulse->stream)
|
||||
{
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
DEBUG_WARN("pa_stream_new failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
pa_context_errno(pulse->context));
|
||||
return FALSE;
|
||||
}
|
||||
pa_stream_set_state_callback(pulse->stream,
|
||||
tsmf_pulse_stream_state_callback, pulse);
|
||||
tsmf_pulse_stream_state_callback, pulse);
|
||||
pa_stream_set_write_callback(pulse->stream,
|
||||
tsmf_pulse_stream_request_callback, pulse);
|
||||
tsmf_pulse_stream_request_callback, pulse);
|
||||
buffer_attr.maxlength = pa_usec_to_bytes(500000, &pulse->sample_spec);
|
||||
buffer_attr.tlength = pa_usec_to_bytes(250000, &pulse->sample_spec);
|
||||
buffer_attr.prebuf = (UINT32) -1;
|
||||
buffer_attr.minreq = (UINT32) -1;
|
||||
buffer_attr.fragsize = (UINT32) -1;
|
||||
if (pa_stream_connect_playback(pulse->stream,
|
||||
pulse->device[0] ? pulse->device : NULL, &buffer_attr,
|
||||
PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE,
|
||||
NULL, NULL) < 0)
|
||||
if(pa_stream_connect_playback(pulse->stream,
|
||||
pulse->device[0] ? pulse->device : NULL, &buffer_attr,
|
||||
PA_STREAM_ADJUST_LATENCY | PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_AUTO_TIMING_UPDATE,
|
||||
NULL, NULL) < 0)
|
||||
{
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
DEBUG_WARN("pa_stream_connect_playback failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
pa_context_errno(pulse->context));
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (;;)
|
||||
for(;;)
|
||||
{
|
||||
state = pa_stream_get_state(pulse->stream);
|
||||
if (state == PA_STREAM_READY)
|
||||
if(state == PA_STREAM_READY)
|
||||
break;
|
||||
if (!PA_STREAM_IS_GOOD(state))
|
||||
if(!PA_STREAM_IS_GOOD(state))
|
||||
{
|
||||
DEBUG_WARN("bad stream state (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
pa_context_errno(pulse->context));
|
||||
break;
|
||||
}
|
||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
||||
}
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
if (state == PA_STREAM_READY)
|
||||
if(state == PA_STREAM_READY)
|
||||
{
|
||||
DEBUG_DVC("connected");
|
||||
DEBUG_TSMF("connected");
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
@ -284,105 +263,93 @@ static BOOL tsmf_pulse_open_stream(TSMFPulseAudioDevice* pulse)
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL tsmf_pulse_set_format(ITSMFAudioDevice* audio,
|
||||
UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample)
|
||||
static BOOL tsmf_pulse_set_format(ITSMFAudioDevice *audio,
|
||||
UINT32 sample_rate, UINT32 channels, UINT32 bits_per_sample)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
|
||||
|
||||
DEBUG_DVC("sample_rate %d channels %d bits_per_sample %d",
|
||||
sample_rate, channels, bits_per_sample);
|
||||
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
DEBUG_TSMF("sample_rate %d channels %d bits_per_sample %d",
|
||||
sample_rate, channels, bits_per_sample);
|
||||
pulse->sample_spec.rate = sample_rate;
|
||||
pulse->sample_spec.channels = channels;
|
||||
pulse->sample_spec.format = PA_SAMPLE_S16LE;
|
||||
|
||||
return tsmf_pulse_open_stream(pulse);
|
||||
}
|
||||
|
||||
static BOOL tsmf_pulse_play(ITSMFAudioDevice* audio, BYTE* data, UINT32 data_size)
|
||||
static BOOL tsmf_pulse_play(ITSMFAudioDevice *audio, BYTE *data, UINT32 data_size)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
|
||||
BYTE* src;
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
BYTE *src;
|
||||
int len;
|
||||
int ret;
|
||||
|
||||
DEBUG_DVC("data_size %d", data_size);
|
||||
|
||||
if (pulse->stream)
|
||||
DEBUG_TSMF("data_size %d", data_size);
|
||||
if(pulse->stream)
|
||||
{
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
|
||||
src = data;
|
||||
while (data_size > 0)
|
||||
while(data_size > 0)
|
||||
{
|
||||
while ((len = pa_stream_writable_size(pulse->stream)) == 0)
|
||||
while((len = pa_stream_writable_size(pulse->stream)) == 0)
|
||||
{
|
||||
DEBUG_DVC("waiting");
|
||||
DEBUG_TSMF("waiting");
|
||||
pa_threaded_mainloop_wait(pulse->mainloop);
|
||||
}
|
||||
if (len < 0)
|
||||
if(len < 0)
|
||||
break;
|
||||
if (len > data_size)
|
||||
if(len > data_size)
|
||||
len = data_size;
|
||||
ret = pa_stream_write(pulse->stream, src, len, NULL, 0LL, PA_SEEK_RELATIVE);
|
||||
if (ret < 0)
|
||||
if(ret < 0)
|
||||
{
|
||||
DEBUG_DVC("pa_stream_write failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
DEBUG_TSMF("pa_stream_write failed (%d)",
|
||||
pa_context_errno(pulse->context));
|
||||
break;
|
||||
}
|
||||
src += len;
|
||||
data_size -= len;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
}
|
||||
free(data);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice* audio)
|
||||
static UINT64 tsmf_pulse_get_latency(ITSMFAudioDevice *audio)
|
||||
{
|
||||
pa_usec_t usec;
|
||||
UINT64 latency = 0;
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
|
||||
|
||||
if (pulse->stream && pa_stream_get_latency(pulse->stream, &usec, NULL) == 0)
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
if(pulse->stream && pa_stream_get_latency(pulse->stream, &usec, NULL) == 0)
|
||||
{
|
||||
latency = ((UINT64)usec) * 10LL;
|
||||
}
|
||||
return latency;
|
||||
}
|
||||
|
||||
static void tsmf_pulse_flush(ITSMFAudioDevice* audio)
|
||||
static void tsmf_pulse_flush(ITSMFAudioDevice *audio)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
|
||||
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
pa_threaded_mainloop_lock(pulse->mainloop);
|
||||
tsmf_pulse_wait_for_operation(pulse,
|
||||
pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse));
|
||||
pa_stream_flush(pulse->stream, tsmf_pulse_stream_success_callback, pulse));
|
||||
pa_threaded_mainloop_unlock(pulse->mainloop);
|
||||
}
|
||||
|
||||
static void tsmf_pulse_free(ITSMFAudioDevice* audio)
|
||||
static void tsmf_pulse_free(ITSMFAudioDevice *audio)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse = (TSMFPulseAudioDevice*) audio;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMFPulseAudioDevice *pulse = (TSMFPulseAudioDevice *) audio;
|
||||
DEBUG_TSMF("");
|
||||
tsmf_pulse_close_stream(pulse);
|
||||
if (pulse->mainloop)
|
||||
if(pulse->mainloop)
|
||||
{
|
||||
pa_threaded_mainloop_stop(pulse->mainloop);
|
||||
}
|
||||
if (pulse->context)
|
||||
if(pulse->context)
|
||||
{
|
||||
pa_context_disconnect(pulse->context);
|
||||
pa_context_unref(pulse->context);
|
||||
pulse->context = NULL;
|
||||
}
|
||||
if (pulse->mainloop)
|
||||
if(pulse->mainloop)
|
||||
{
|
||||
pa_threaded_mainloop_free(pulse->mainloop);
|
||||
pulse->mainloop = NULL;
|
||||
@ -394,20 +361,17 @@ static void tsmf_pulse_free(ITSMFAudioDevice* audio)
|
||||
#define freerdp_tsmf_client_audio_subsystem_entry pulse_freerdp_tsmf_client_audio_subsystem_entry
|
||||
#endif
|
||||
|
||||
ITSMFAudioDevice* freerdp_tsmf_client_audio_subsystem_entry(void)
|
||||
ITSMFAudioDevice *freerdp_tsmf_client_audio_subsystem_entry(void)
|
||||
{
|
||||
TSMFPulseAudioDevice* pulse;
|
||||
|
||||
pulse = (TSMFPulseAudioDevice*) malloc(sizeof(TSMFPulseAudioDevice));
|
||||
TSMFPulseAudioDevice *pulse;
|
||||
pulse = (TSMFPulseAudioDevice *) malloc(sizeof(TSMFPulseAudioDevice));
|
||||
ZeroMemory(pulse, sizeof(TSMFPulseAudioDevice));
|
||||
|
||||
pulse->iface.Open = tsmf_pulse_open;
|
||||
pulse->iface.SetFormat = tsmf_pulse_set_format;
|
||||
pulse->iface.Play = tsmf_pulse_play;
|
||||
pulse->iface.GetLatency = tsmf_pulse_get_latency;
|
||||
pulse->iface.Flush = tsmf_pulse_flush;
|
||||
pulse->iface.Free = tsmf_pulse_free;
|
||||
|
||||
return (ITSMFAudioDevice*) pulse;
|
||||
return (ITSMFAudioDevice *) pulse;
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@
|
||||
typedef struct _TSMFMediaTypeMap
|
||||
{
|
||||
BYTE guid[16];
|
||||
const char* name;
|
||||
const char *name;
|
||||
int type;
|
||||
} TSMFMediaTypeMap;
|
||||
|
||||
@ -259,24 +259,23 @@ static const TSMFMediaTypeMap tsmf_format_type_map[] =
|
||||
}
|
||||
};
|
||||
|
||||
static void tsmf_print_guid(const BYTE* guid)
|
||||
static void tsmf_print_guid(const BYTE *guid)
|
||||
{
|
||||
#ifdef WITH_DEBUG_DVC
|
||||
#ifdef WITH_DEBUG_TSMF
|
||||
int i;
|
||||
|
||||
for (i = 3; i >= 0; i--)
|
||||
for(i = 3; i >= 0; i--)
|
||||
fprintf(stderr, "%02X", guid[i]);
|
||||
fprintf(stderr, "-");
|
||||
for (i = 5; i >= 4; i--)
|
||||
for(i = 5; i >= 4; i--)
|
||||
fprintf(stderr, "%02X", guid[i]);
|
||||
fprintf(stderr, "-");
|
||||
for (i = 7; i >= 6; i--)
|
||||
for(i = 7; i >= 6; i--)
|
||||
fprintf(stderr, "%02X", guid[i]);
|
||||
fprintf(stderr, "-");
|
||||
for (i = 8; i < 16; i++)
|
||||
for(i = 8; i < 16; i++)
|
||||
{
|
||||
fprintf(stderr, "%02X", guid[i]);
|
||||
if (i == 9)
|
||||
if(i == 9)
|
||||
fprintf(stderr, "-");
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
@ -284,34 +283,29 @@ static void tsmf_print_guid(const BYTE* guid)
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/dd318229.aspx */
|
||||
static UINT32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wStream* s, BOOL bypass)
|
||||
static UINT32 tsmf_codec_parse_BITMAPINFOHEADER(TS_AM_MEDIA_TYPE *mediatype, wStream *s, BOOL bypass)
|
||||
{
|
||||
UINT32 biSize;
|
||||
UINT32 biWidth;
|
||||
UINT32 biHeight;
|
||||
|
||||
Stream_Read_UINT32(s, biSize);
|
||||
Stream_Read_UINT32(s, biWidth);
|
||||
Stream_Read_UINT32(s, biHeight);
|
||||
Stream_Seek(s, 28);
|
||||
|
||||
if (mediatype->Width == 0)
|
||||
if(mediatype->Width == 0)
|
||||
mediatype->Width = biWidth;
|
||||
if (mediatype->Height == 0)
|
||||
if(mediatype->Height == 0)
|
||||
mediatype->Height = biHeight;
|
||||
/* Assume there will be no color table for video? */
|
||||
|
||||
if (bypass && biSize > 40)
|
||||
if(bypass && biSize > 40)
|
||||
Stream_Seek(s, biSize - 40);
|
||||
|
||||
return (bypass ? biSize : 40);
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/dd407326.aspx */
|
||||
static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
|
||||
static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE *mediatype, wStream *s)
|
||||
{
|
||||
UINT64 AvgTimePerFrame;
|
||||
|
||||
/* VIDEOINFOHEADER2.rcSource, RECT(LONG left, LONG top, LONG right, LONG bottom) */
|
||||
Stream_Seek_UINT32(s);
|
||||
Stream_Seek_UINT32(s);
|
||||
@ -329,25 +323,23 @@ static UINT32 tsmf_codec_parse_VIDEOINFOHEADER2(TS_AM_MEDIA_TYPE* mediatype, wSt
|
||||
mediatype->SamplesPerSecond.Denominator = (int)(AvgTimePerFrame / 10LL);
|
||||
/* Remaining fields before bmiHeader */
|
||||
Stream_Seek(s, 24);
|
||||
|
||||
return 72;
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/dd390700.aspx */
|
||||
static UINT32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
|
||||
static UINT32 tsmf_codec_parse_VIDEOINFOHEADER(TS_AM_MEDIA_TYPE *mediatype, wStream *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;
|
||||
*/
|
||||
/*
|
||||
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);
|
||||
@ -363,76 +355,66 @@ typedef struct tagVIDEOINFOHEADER {
|
||||
Stream_Read_UINT64(s, AvgTimePerFrame);
|
||||
mediatype->SamplesPerSecond.Numerator = 1000000;
|
||||
mediatype->SamplesPerSecond.Denominator = (int)(AvgTimePerFrame / 10LL);
|
||||
|
||||
return 48;
|
||||
}
|
||||
|
||||
BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
|
||||
BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE *mediatype, wStream *s)
|
||||
{
|
||||
int i;
|
||||
UINT32 cbFormat;
|
||||
BOOL ret = TRUE;
|
||||
|
||||
memset(mediatype, 0, sizeof(TS_AM_MEDIA_TYPE));
|
||||
|
||||
/* MajorType */
|
||||
DEBUG_DVC("MajorType:");
|
||||
DEBUG_TSMF("MajorType:");
|
||||
tsmf_print_guid(Stream_Pointer(s));
|
||||
for (i = 0; tsmf_major_type_map[i].type != TSMF_MAJOR_TYPE_UNKNOWN; i++)
|
||||
for(i = 0; tsmf_major_type_map[i].type != TSMF_MAJOR_TYPE_UNKNOWN; i++)
|
||||
{
|
||||
if (memcmp(tsmf_major_type_map[i].guid, Stream_Pointer(s), 16) == 0)
|
||||
if(memcmp(tsmf_major_type_map[i].guid, Stream_Pointer(s), 16) == 0)
|
||||
break;
|
||||
}
|
||||
mediatype->MajorType = tsmf_major_type_map[i].type;
|
||||
if (mediatype->MajorType == TSMF_MAJOR_TYPE_UNKNOWN)
|
||||
if(mediatype->MajorType == TSMF_MAJOR_TYPE_UNKNOWN)
|
||||
ret = FALSE;
|
||||
DEBUG_DVC("MajorType %s", tsmf_major_type_map[i].name);
|
||||
DEBUG_TSMF("MajorType %s", tsmf_major_type_map[i].name);
|
||||
Stream_Seek(s, 16);
|
||||
|
||||
/* SubType */
|
||||
DEBUG_DVC("SubType:");
|
||||
DEBUG_TSMF("SubType:");
|
||||
tsmf_print_guid(Stream_Pointer(s));
|
||||
for (i = 0; tsmf_sub_type_map[i].type != TSMF_SUB_TYPE_UNKNOWN; i++)
|
||||
for(i = 0; tsmf_sub_type_map[i].type != TSMF_SUB_TYPE_UNKNOWN; i++)
|
||||
{
|
||||
if (memcmp(tsmf_sub_type_map[i].guid, Stream_Pointer(s), 16) == 0)
|
||||
if(memcmp(tsmf_sub_type_map[i].guid, Stream_Pointer(s), 16) == 0)
|
||||
break;
|
||||
}
|
||||
mediatype->SubType = tsmf_sub_type_map[i].type;
|
||||
if (mediatype->SubType == TSMF_SUB_TYPE_UNKNOWN)
|
||||
if(mediatype->SubType == TSMF_SUB_TYPE_UNKNOWN)
|
||||
ret = FALSE;
|
||||
DEBUG_DVC("SubType %s", tsmf_sub_type_map[i].name);
|
||||
DEBUG_TSMF("SubType %s", tsmf_sub_type_map[i].name);
|
||||
Stream_Seek(s, 16);
|
||||
|
||||
/* bFixedSizeSamples, bTemporalCompression, SampleSize */
|
||||
Stream_Seek(s, 12);
|
||||
|
||||
/* FormatType */
|
||||
DEBUG_DVC("FormatType:");
|
||||
DEBUG_TSMF("FormatType:");
|
||||
tsmf_print_guid(Stream_Pointer(s));
|
||||
for (i = 0; tsmf_format_type_map[i].type != TSMF_FORMAT_TYPE_UNKNOWN; i++)
|
||||
for(i = 0; tsmf_format_type_map[i].type != TSMF_FORMAT_TYPE_UNKNOWN; i++)
|
||||
{
|
||||
if (memcmp(tsmf_format_type_map[i].guid, Stream_Pointer(s), 16) == 0)
|
||||
if(memcmp(tsmf_format_type_map[i].guid, Stream_Pointer(s), 16) == 0)
|
||||
break;
|
||||
}
|
||||
mediatype->FormatType = tsmf_format_type_map[i].type;
|
||||
if (mediatype->FormatType == TSMF_FORMAT_TYPE_UNKNOWN)
|
||||
if(mediatype->FormatType == TSMF_FORMAT_TYPE_UNKNOWN)
|
||||
ret = FALSE;
|
||||
DEBUG_DVC("FormatType %s", tsmf_format_type_map[i].name);
|
||||
DEBUG_TSMF("FormatType %s", tsmf_format_type_map[i].name);
|
||||
Stream_Seek(s, 16);
|
||||
|
||||
/* cbFormat */
|
||||
Stream_Read_UINT32(s, cbFormat);
|
||||
DEBUG_DVC("cbFormat %d", cbFormat);
|
||||
|
||||
#ifdef WITH_DEBUG_DVC
|
||||
DEBUG_TSMF("cbFormat %d", cbFormat);
|
||||
#ifdef WITH_DEBUG_TSMF
|
||||
winpr_HexDump(Stream_Pointer(s), cbFormat);
|
||||
#endif
|
||||
|
||||
switch (mediatype->FormatType)
|
||||
switch(mediatype->FormatType)
|
||||
{
|
||||
case TSMF_FORMAT_TYPE_MFVIDEOFORMAT:
|
||||
/* http://msdn.microsoft.com/en-us/library/aa473808.aspx */
|
||||
|
||||
Stream_Seek(s, 8); /* dwSize and ? */
|
||||
Stream_Read_UINT32(s, mediatype->Width); /* videoInfo.dwWidth */
|
||||
Stream_Read_UINT32(s, mediatype->Height); /* videoInfo.dwHeight */
|
||||
@ -443,17 +425,14 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
|
||||
Stream_Seek(s, 80);
|
||||
Stream_Read_UINT32(s, mediatype->BitRate); /* compressedInfo.AvgBitrate */
|
||||
Stream_Seek(s, 36);
|
||||
|
||||
if (cbFormat > 176)
|
||||
if(cbFormat > 176)
|
||||
{
|
||||
mediatype->ExtraDataSize = cbFormat - 176;
|
||||
mediatype->ExtraData = Stream_Pointer(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case TSMF_FORMAT_TYPE_WAVEFORMATEX:
|
||||
/* http://msdn.microsoft.com/en-us/library/dd757720.aspx */
|
||||
|
||||
Stream_Seek_UINT16(s);
|
||||
Stream_Read_UINT16(s, mediatype->Channels);
|
||||
Stream_Read_UINT32(s, mediatype->SamplesPerSecond.Numerator);
|
||||
@ -463,66 +442,55 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s)
|
||||
Stream_Read_UINT16(s, mediatype->BlockAlign);
|
||||
Stream_Read_UINT16(s, mediatype->BitsPerSample);
|
||||
Stream_Read_UINT16(s, mediatype->ExtraDataSize);
|
||||
if (mediatype->ExtraDataSize > 0)
|
||||
if(mediatype->ExtraDataSize > 0)
|
||||
mediatype->ExtraData = Stream_Pointer(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)
|
||||
if(cbFormat > i)
|
||||
{
|
||||
mediatype->ExtraDataSize = cbFormat - i;
|
||||
mediatype->ExtraData = Stream_Pointer(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case TSMF_FORMAT_TYPE_MPEG2VIDEOINFO:
|
||||
/* http://msdn.microsoft.com/en-us/library/dd390707.aspx */
|
||||
|
||||
i = tsmf_codec_parse_VIDEOINFOHEADER2(mediatype, s);
|
||||
i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, TRUE);
|
||||
if (cbFormat > i)
|
||||
if(cbFormat > i)
|
||||
{
|
||||
mediatype->ExtraDataSize = cbFormat - i;
|
||||
mediatype->ExtraData = Stream_Pointer(s);
|
||||
}
|
||||
break;
|
||||
|
||||
case TSMF_FORMAT_TYPE_VIDEOINFO2:
|
||||
i = tsmf_codec_parse_VIDEOINFOHEADER2(mediatype, s);
|
||||
i += tsmf_codec_parse_BITMAPINFOHEADER(mediatype, s, FALSE);
|
||||
if (cbFormat > i)
|
||||
if(cbFormat > i)
|
||||
{
|
||||
mediatype->ExtraDataSize = cbFormat - i;
|
||||
mediatype->ExtraData = Stream_Pointer(s);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (mediatype->SamplesPerSecond.Numerator == 0)
|
||||
if(mediatype->SamplesPerSecond.Numerator == 0)
|
||||
mediatype->SamplesPerSecond.Numerator = 1;
|
||||
if (mediatype->SamplesPerSecond.Denominator == 0)
|
||||
if(mediatype->SamplesPerSecond.Denominator == 0)
|
||||
mediatype->SamplesPerSecond.Denominator = 1;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BOOL tsmf_codec_check_media_type(wStream* s)
|
||||
BOOL tsmf_codec_check_media_type(wStream *s)
|
||||
{
|
||||
BYTE* m;
|
||||
BYTE *m;
|
||||
BOOL ret;
|
||||
TS_AM_MEDIA_TYPE mediatype;
|
||||
|
||||
Stream_GetPointer(s, m);
|
||||
ret = tsmf_codec_parse_media_type(&mediatype, s);
|
||||
Stream_SetPointer(s, m);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
@ -32,45 +32,41 @@
|
||||
#include "tsmf_constants.h"
|
||||
#include "tsmf_decoder.h"
|
||||
|
||||
static ITSMFDecoder* tsmf_load_decoder_by_name(const char* name, TS_AM_MEDIA_TYPE* media_type)
|
||||
static ITSMFDecoder *tsmf_load_decoder_by_name(const char *name, TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
ITSMFDecoder* decoder;
|
||||
ITSMFDecoder *decoder;
|
||||
TSMF_DECODER_ENTRY entry;
|
||||
|
||||
entry = (TSMF_DECODER_ENTRY) freerdp_load_channel_addin_entry("tsmf", (LPSTR) name, "decoder", 0);
|
||||
|
||||
if (entry == NULL)
|
||||
if(entry == NULL)
|
||||
return NULL;
|
||||
|
||||
decoder = entry();
|
||||
|
||||
if (decoder == NULL)
|
||||
if(decoder == NULL)
|
||||
{
|
||||
DEBUG_WARN("failed to call export function in %s", name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!decoder->SetFormat(decoder, media_type))
|
||||
if(!decoder->SetFormat(decoder, media_type))
|
||||
{
|
||||
decoder->Free(decoder);
|
||||
decoder = NULL;
|
||||
}
|
||||
|
||||
return decoder;
|
||||
}
|
||||
|
||||
ITSMFDecoder* tsmf_load_decoder(const char* name, TS_AM_MEDIA_TYPE* media_type)
|
||||
ITSMFDecoder *tsmf_load_decoder(const char *name, TS_AM_MEDIA_TYPE *media_type)
|
||||
{
|
||||
ITSMFDecoder* decoder;
|
||||
|
||||
if (name)
|
||||
ITSMFDecoder *decoder = NULL;
|
||||
if(name)
|
||||
{
|
||||
decoder = tsmf_load_decoder_by_name(name, media_type);
|
||||
}
|
||||
else
|
||||
{
|
||||
#if defined(WITH_GSTREAMER_1_0) || defined(WITH_GSTREAMER_0_10)
|
||||
if(!decoder)
|
||||
decoder = tsmf_load_decoder_by_name("gstreamer", media_type);
|
||||
#endif
|
||||
#if defined(WITH_FFMPEG)
|
||||
if(!decoder)
|
||||
decoder = tsmf_load_decoder_by_name("ffmpeg", media_type);
|
||||
}
|
||||
|
||||
#endif
|
||||
return decoder;
|
||||
}
|
||||
|
@ -26,9 +26,8 @@
|
||||
typedef enum _ITSMFControlMsg
|
||||
{
|
||||
Control_Pause,
|
||||
Control_Restart,
|
||||
Control_Flush,
|
||||
Control_EndOfStream
|
||||
Control_Resume,
|
||||
Control_Stop
|
||||
} ITSMFControlMsg;
|
||||
|
||||
typedef struct _ITSMFDecoder ITSMFDecoder;
|
||||
@ -36,36 +35,40 @@ typedef struct _ITSMFDecoder ITSMFDecoder;
|
||||
struct _ITSMFDecoder
|
||||
{
|
||||
/* Set the decoder format. Return true if supported. */
|
||||
BOOL (*SetFormat) (ITSMFDecoder* decoder, TS_AM_MEDIA_TYPE* media_type);
|
||||
BOOL (*SetFormat)(ITSMFDecoder *decoder, TS_AM_MEDIA_TYPE *media_type);
|
||||
/* Decode a sample. */
|
||||
BOOL (*Decode) (ITSMFDecoder* decoder, const BYTE* data, UINT32 data_size, UINT32 extensions);
|
||||
BOOL (*Decode)(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions);
|
||||
/* Get the decoded data */
|
||||
BYTE* (*GetDecodedData) (ITSMFDecoder* decoder, UINT32* size);
|
||||
BYTE *(*GetDecodedData)(ITSMFDecoder *decoder, UINT32 *size);
|
||||
/* Get the pixel format of decoded video frame */
|
||||
UINT32 (*GetDecodedFormat) (ITSMFDecoder* decoder);
|
||||
UINT32(*GetDecodedFormat)(ITSMFDecoder *decoder);
|
||||
/* Get the width and height of decoded video frame */
|
||||
BOOL (*GetDecodedDimension) (ITSMFDecoder* decoder, UINT32* width, UINT32* height);
|
||||
BOOL (*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);
|
||||
void (*Control)(ITSMFDecoder *decoder, ITSMFControlMsg control_msg, UINT32 *arg);
|
||||
/* Decode a sample with extended interface. */
|
||||
int (*DecodeEx) (ITSMFDecoder * decoder, const BYTE * data, UINT32 data_size, UINT32 extensions,
|
||||
UINT64 start_time, UINT64 end_time, UINT64 duration);
|
||||
int (*DecodeEx)(ITSMFDecoder *decoder, const BYTE *data, UINT32 data_size, UINT32 extensions,
|
||||
UINT64 start_time, UINT64 end_time, UINT64 duration);
|
||||
/* Get current play time */
|
||||
UINT64 (*GetRunningTime) (ITSMFDecoder * decoder);
|
||||
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);
|
||||
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);
|
||||
void (*ChangeVolume)(ITSMFDecoder *decoder, UINT32 newVolume, UINT32 muted);
|
||||
/* Check buffer level */
|
||||
UINT32 (*BufferLevel) (ITSMFDecoder * decoder);
|
||||
BOOL (*BufferFilled)(ITSMFDecoder *decoder);
|
||||
/* Register a callback for frame ack. */
|
||||
BOOL (*SetAckFunc)(ITSMFDecoder *decoder, BOOL (*cb)(void *,BOOL), void *stream);
|
||||
/* Register a callback for stream seek detection. */
|
||||
BOOL (*SetSyncFunc)(ITSMFDecoder *decoder, void (*cb)(void *), void *stream);
|
||||
};
|
||||
|
||||
#define TSMF_DECODER_EXPORT_FUNC_NAME "TSMFDecoderEntry"
|
||||
typedef ITSMFDecoder* (*TSMF_DECODER_ENTRY) (void);
|
||||
typedef ITSMFDecoder *(*TSMF_DECODER_ENTRY)(void);
|
||||
|
||||
ITSMFDecoder* tsmf_load_decoder(const char* name, TS_AM_MEDIA_TYPE* media_type);
|
||||
ITSMFDecoder *tsmf_load_decoder(const char *name, TS_AM_MEDIA_TYPE *media_type);
|
||||
|
||||
#endif
|
||||
|
||||
|
@ -37,21 +37,18 @@
|
||||
|
||||
#include "tsmf_ifman.h"
|
||||
|
||||
int tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_rim_exchange_capability_request(TSMF_IFMAN *ifman)
|
||||
{
|
||||
UINT32 CapabilityValue;
|
||||
|
||||
Stream_Read_UINT32(ifman->input, CapabilityValue);
|
||||
DEBUG_DVC("server CapabilityValue %d", CapabilityValue);
|
||||
|
||||
DEBUG_TSMF("server CapabilityValue %d", CapabilityValue);
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 8);
|
||||
Stream_Write_UINT32(ifman->output, 1); /* CapabilityValue */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_exchange_capability_request(TSMF_IFMAN *ifman)
|
||||
{
|
||||
UINT32 i;
|
||||
UINT32 v;
|
||||
@ -59,32 +56,28 @@ int tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
|
||||
UINT32 CapabilityType;
|
||||
UINT32 cbCapabilityLength;
|
||||
UINT32 numHostCapabilities;
|
||||
|
||||
pos = Stream_GetPosition(ifman->output);
|
||||
Stream_EnsureRemainingCapacity(ifman->output, ifman->input_size + 4);
|
||||
Stream_Copy(ifman->output, ifman->input, ifman->input_size);
|
||||
|
||||
Stream_SetPosition(ifman->output, pos);
|
||||
Stream_Read_UINT32(ifman->output, numHostCapabilities);
|
||||
|
||||
for (i = 0; i < numHostCapabilities; i++)
|
||||
for(i = 0; i < numHostCapabilities; i++)
|
||||
{
|
||||
Stream_Read_UINT32(ifman->output, CapabilityType);
|
||||
Stream_Read_UINT32(ifman->output, cbCapabilityLength);
|
||||
pos = Stream_GetPosition(ifman->output);
|
||||
|
||||
switch (CapabilityType)
|
||||
switch(CapabilityType)
|
||||
{
|
||||
case 1: /* Protocol version request */
|
||||
Stream_Read_UINT32(ifman->output, v);
|
||||
DEBUG_DVC("server protocol version %d", v);
|
||||
DEBUG_TSMF("server protocol version %d", v);
|
||||
break;
|
||||
case 2: /* Supported platform */
|
||||
Stream_Peek_UINT32(ifman->output, v);
|
||||
DEBUG_DVC("server supported platform %d", v);
|
||||
DEBUG_TSMF("server supported platform %d", v);
|
||||
/* Claim that we support both MF and DShow platforms. */
|
||||
Stream_Write_UINT32(ifman->output,
|
||||
MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW);
|
||||
MMREDIR_CAPABILITY_PLATFORM_MF | MMREDIR_CAPABILITY_PLATFORM_DSHOW);
|
||||
break;
|
||||
default:
|
||||
DEBUG_WARN("unknown capability type %d", CapabilityType);
|
||||
@ -93,81 +86,62 @@ int tsmf_ifman_exchange_capability_request(TSMF_IFMAN* ifman)
|
||||
Stream_SetPosition(ifman->output, pos + cbCapabilityLength);
|
||||
}
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
|
||||
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_check_format_support_request(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_check_format_support_request(TSMF_IFMAN *ifman)
|
||||
{
|
||||
UINT32 numMediaType;
|
||||
UINT32 PlatformCookie;
|
||||
UINT32 FormatSupported = 1;
|
||||
|
||||
Stream_Read_UINT32(ifman->input, PlatformCookie);
|
||||
Stream_Seek_UINT32(ifman->input); /* NoRolloverFlags (4 bytes) */
|
||||
Stream_Read_UINT32(ifman->input, numMediaType);
|
||||
|
||||
DEBUG_DVC("PlatformCookie %d numMediaType %d", PlatformCookie, numMediaType);
|
||||
|
||||
if (!tsmf_codec_check_media_type(ifman->input))
|
||||
DEBUG_TSMF("PlatformCookie %d numMediaType %d", PlatformCookie, numMediaType);
|
||||
if(!tsmf_codec_check_media_type(ifman->input))
|
||||
FormatSupported = 0;
|
||||
|
||||
if (FormatSupported)
|
||||
DEBUG_DVC("format ok.");
|
||||
|
||||
if(FormatSupported)
|
||||
DEBUG_TSMF("format ok.");
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 12);
|
||||
Stream_Write_UINT32(ifman->output, FormatSupported);
|
||||
Stream_Write_UINT32(ifman->output, PlatformCookie);
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
|
||||
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_new_presentation(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_new_presentation(TSMF_IFMAN *ifman)
|
||||
{
|
||||
int status = 0;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
{
|
||||
DEBUG_DVC("Presentation already exists");
|
||||
DEBUG_TSMF("Presentation already exists");
|
||||
ifman->output_pending = FALSE;
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
presentation = tsmf_presentation_new(Stream_Pointer(ifman->input), ifman->channel_callback);
|
||||
|
||||
if (presentation == NULL)
|
||||
if(presentation == NULL)
|
||||
status = 1;
|
||||
else
|
||||
tsmf_presentation_set_audio_device(presentation, ifman->audio_name, ifman->audio_device);
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int tsmf_ifman_add_stream(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_add_stream(TSMF_IFMAN *ifman)
|
||||
{
|
||||
UINT32 StreamId;
|
||||
int status = 0;
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
Stream_Seek(ifman->input, 16);
|
||||
|
||||
if (presentation == NULL)
|
||||
if(presentation == NULL)
|
||||
{
|
||||
status = 1;
|
||||
}
|
||||
@ -176,41 +150,33 @@ int tsmf_ifman_add_stream(TSMF_IFMAN* ifman)
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
Stream_Seek_UINT32(ifman->input); /* numMediaType */
|
||||
stream = tsmf_stream_new(presentation, StreamId);
|
||||
|
||||
if (stream)
|
||||
if(stream)
|
||||
tsmf_stream_set_format(stream, ifman->decoder_name, ifman->input);
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int tsmf_ifman_set_topology_request(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_set_topology_request(TSMF_IFMAN *ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
|
||||
DEBUG_TSMF("");
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 8);
|
||||
Stream_Write_UINT32(ifman->output, 1); /* TopologyReady */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_remove_stream(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_remove_stream(TSMF_IFMAN *ifman)
|
||||
{
|
||||
int status = 0;
|
||||
UINT32 StreamId;
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
Stream_Seek(ifman->input, 16);
|
||||
|
||||
if (presentation == NULL)
|
||||
if(presentation == NULL)
|
||||
{
|
||||
status = 1;
|
||||
}
|
||||
@ -218,41 +184,34 @@ int tsmf_ifman_remove_stream(TSMF_IFMAN* ifman)
|
||||
{
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
stream = tsmf_stream_find_by_id(presentation, StreamId);
|
||||
if (stream)
|
||||
if(stream)
|
||||
tsmf_stream_free(stream);
|
||||
else
|
||||
status = 1;
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
float tsmf_stream_read_float(wStream* s)
|
||||
float tsmf_stream_read_float(wStream *s)
|
||||
{
|
||||
float fValue;
|
||||
UINT32 iValue;
|
||||
|
||||
Stream_Read_UINT32(s, iValue);
|
||||
CopyMemory(&fValue, &iValue, 4);
|
||||
|
||||
return fValue;
|
||||
}
|
||||
|
||||
int tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_set_source_video_rect(TSMF_IFMAN *ifman)
|
||||
{
|
||||
int status = 0;
|
||||
float Left, Top;
|
||||
float Right, Bottom;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
Stream_Seek(ifman->input, 16);
|
||||
|
||||
if (!presentation)
|
||||
if(!presentation)
|
||||
{
|
||||
status = 1;
|
||||
}
|
||||
@ -262,144 +221,117 @@ int tsmf_ifman_set_source_video_rect(TSMF_IFMAN* ifman)
|
||||
Top = tsmf_stream_read_float(ifman->input); /* Top (4 bytes) */
|
||||
Right = tsmf_stream_read_float(ifman->input); /* Right (4 bytes) */
|
||||
Bottom = tsmf_stream_read_float(ifman->input); /* Bottom (4 bytes) */
|
||||
|
||||
DEBUG_DVC("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f",
|
||||
Left, Top, Right, Bottom);
|
||||
DEBUG_TSMF("SetSourceVideoRect: Left: %f Top: %f Right: %f Bottom: %f",
|
||||
Left, Top, Right, Bottom);
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
int tsmf_ifman_shutdown_presentation(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_shutdown_presentation(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
tsmf_presentation_free(presentation);
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 4);
|
||||
Stream_Write_UINT32(ifman->output, 0); /* Result */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_DEFAULT | STREAM_ID_STUB;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_stream_volume(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_stream_volume(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("on stream volume");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("on stream volume");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
{
|
||||
UINT32 newVolume;
|
||||
UINT32 muted;
|
||||
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, newVolume);
|
||||
DEBUG_DVC("on stream volume: new volume=[%d]", newVolume);
|
||||
DEBUG_TSMF("on stream volume: new volume=[%d]", newVolume);
|
||||
Stream_Read_UINT32(ifman->input, muted);
|
||||
DEBUG_DVC("on stream volume: muted=[%d]", muted);
|
||||
DEBUG_TSMF("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)
|
||||
int tsmf_ifman_on_channel_volume(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("on channel volume");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("on channel volume");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
{
|
||||
UINT32 channelVolume;
|
||||
UINT32 changedChannel;
|
||||
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, channelVolume);
|
||||
DEBUG_DVC("on channel volume: channel volume=[%d]", channelVolume);
|
||||
DEBUG_TSMF("on channel volume: channel volume=[%d]", channelVolume);
|
||||
Stream_Read_UINT32(ifman->input, changedChannel);
|
||||
DEBUG_DVC("on stream volume: changed channel=[%d]", changedChannel);
|
||||
DEBUG_TSMF("on stream volume: changed channel=[%d]", changedChannel);
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_set_video_window(TSMF_IFMAN* ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
ifman->output_pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_set_video_window(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_update_geometry_info(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION *presentation;
|
||||
UINT32 numGeometryInfo;
|
||||
UINT32 Left;
|
||||
UINT32 Top;
|
||||
UINT32 Width;
|
||||
UINT32 Height;
|
||||
UINT32 cbVisibleRect;
|
||||
RDP_RECT* rects = NULL;
|
||||
RDP_RECT *rects = NULL;
|
||||
int num_rects = 0;
|
||||
int error = 0;
|
||||
int i;
|
||||
int pos;
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
Stream_Seek(ifman->input, 16);
|
||||
|
||||
Stream_Read_UINT32(ifman->input, numGeometryInfo);
|
||||
pos = Stream_GetPosition(ifman->input);
|
||||
|
||||
Stream_Seek(ifman->input, 12); /* VideoWindowId (8 bytes), VideoWindowState (4 bytes) */
|
||||
Stream_Read_UINT32(ifman->input, Width);
|
||||
Stream_Read_UINT32(ifman->input, Height);
|
||||
Stream_Read_UINT32(ifman->input, Left);
|
||||
Stream_Read_UINT32(ifman->input, Top);
|
||||
|
||||
Stream_SetPosition(ifman->input, pos + numGeometryInfo);
|
||||
Stream_Read_UINT32(ifman->input, cbVisibleRect);
|
||||
num_rects = cbVisibleRect / 16;
|
||||
|
||||
DEBUG_DVC("numGeometryInfo %d Width %d Height %d Left %d Top %d cbVisibleRect %d num_rects %d",
|
||||
numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
|
||||
|
||||
if (presentation == NULL)
|
||||
DEBUG_TSMF("numGeometryInfo %d Width %d Height %d Left %d Top %d cbVisibleRect %d num_rects %d",
|
||||
numGeometryInfo, Width, Height, Left, Top, cbVisibleRect, num_rects);
|
||||
if(presentation == NULL)
|
||||
{
|
||||
error = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (num_rects > 0)
|
||||
if(num_rects > 0)
|
||||
{
|
||||
rects = (RDP_RECT*) malloc(sizeof(RDP_RECT) * num_rects);
|
||||
rects = (RDP_RECT *) malloc(sizeof(RDP_RECT) * num_rects);
|
||||
ZeroMemory(rects, sizeof(RDP_RECT) * num_rects);
|
||||
|
||||
for (i = 0; i < num_rects; i++)
|
||||
for(i = 0; i < num_rects; i++)
|
||||
{
|
||||
Stream_Read_UINT16(ifman->input, rects[i].y); /* Top */
|
||||
Stream_Seek_UINT16(ifman->input);
|
||||
@ -411,44 +343,40 @@ int tsmf_ifman_update_geometry_info(TSMF_IFMAN* ifman)
|
||||
Stream_Seek_UINT16(ifman->input);
|
||||
rects[i].width -= rects[i].x;
|
||||
rects[i].height -= rects[i].y;
|
||||
|
||||
DEBUG_DVC("rect %d: %d %d %d %d", i,
|
||||
rects[i].x, rects[i].y, rects[i].width, rects[i].height);
|
||||
DEBUG_TSMF("rect %d: %d %d %d %d", i,
|
||||
rects[i].x, rects[i].y, rects[i].width, rects[i].height);
|
||||
}
|
||||
}
|
||||
tsmf_presentation_set_geometry_info(presentation, Left, Top, Width, Height, num_rects, rects);
|
||||
}
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
int tsmf_ifman_set_allocator(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_set_allocator(TSMF_IFMAN *ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_notify_preroll(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_notify_preroll(TSMF_IFMAN *ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_sample(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_STREAM *stream;
|
||||
UINT32 StreamId;
|
||||
UINT64 SampleStartTime;
|
||||
UINT64 SampleEndTime;
|
||||
UINT64 ThrottleDuration;
|
||||
UINT32 SampleExtensions;
|
||||
UINT32 cbData;
|
||||
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
Stream_Seek_UINT32(ifman->input); /* numSample */
|
||||
@ -458,183 +386,144 @@ int tsmf_ifman_on_sample(TSMF_IFMAN* ifman)
|
||||
Stream_Seek_UINT32(ifman->input); /* SampleFlags */
|
||||
Stream_Read_UINT32(ifman->input, SampleExtensions);
|
||||
Stream_Read_UINT32(ifman->input, cbData);
|
||||
|
||||
DEBUG_DVC("MessageId %d StreamId %d SampleStartTime %d SampleEndTime %d "
|
||||
"ThrottleDuration %d SampleExtensions %d cbData %d",
|
||||
ifman->message_id, StreamId, (int)SampleStartTime, (int)SampleEndTime,
|
||||
(int)ThrottleDuration, SampleExtensions, cbData);
|
||||
|
||||
DEBUG_TSMF("MessageId %d StreamId %d SampleStartTime %d SampleEndTime %d "
|
||||
"ThrottleDuration %d SampleExtensions %d cbData %d",
|
||||
ifman->message_id, StreamId, (int)SampleStartTime, (int)SampleEndTime,
|
||||
(int)ThrottleDuration, SampleExtensions, cbData);
|
||||
presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
|
||||
|
||||
if (presentation == NULL)
|
||||
if(presentation == NULL)
|
||||
{
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
return 1;
|
||||
}
|
||||
|
||||
stream = tsmf_stream_find_by_id(presentation, StreamId);
|
||||
|
||||
if (stream == NULL)
|
||||
if(stream == NULL)
|
||||
{
|
||||
DEBUG_WARN("unknown stream id");
|
||||
return 1;
|
||||
}
|
||||
|
||||
tsmf_stream_push_sample(stream, ifman->channel_callback,
|
||||
ifman->message_id, SampleStartTime, SampleEndTime, ThrottleDuration, SampleExtensions,
|
||||
cbData, Stream_Pointer(ifman->input));
|
||||
|
||||
ifman->message_id, SampleStartTime, SampleEndTime, ThrottleDuration, SampleExtensions,
|
||||
cbData, Stream_Pointer(ifman->input));
|
||||
tsmf_presentation_sync(presentation);
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_flush(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_flush(TSMF_IFMAN *ifman)
|
||||
{
|
||||
UINT32 StreamId;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
DEBUG_DVC("StreamId %d", StreamId);
|
||||
|
||||
DEBUG_TSMF("StreamId %d", StreamId);
|
||||
presentation = tsmf_presentation_find_by_id(ifman->presentation_id);
|
||||
|
||||
if (presentation == NULL)
|
||||
if(presentation == NULL)
|
||||
{
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
return 1;
|
||||
}
|
||||
|
||||
tsmf_presentation_flush(presentation);
|
||||
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_end_of_stream(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_end_of_stream(TSMF_IFMAN *ifman)
|
||||
{
|
||||
UINT32 StreamId;
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
Stream_Seek(ifman->input, 16);
|
||||
Stream_Read_UINT32(ifman->input, StreamId);
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
{
|
||||
stream = tsmf_stream_find_by_id(presentation, StreamId);
|
||||
if (stream)
|
||||
if(stream)
|
||||
tsmf_stream_end(stream);
|
||||
}
|
||||
DEBUG_DVC("StreamId %d", StreamId);
|
||||
|
||||
DEBUG_TSMF("StreamId %d", StreamId);
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 16);
|
||||
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
|
||||
Stream_Write_UINT32(ifman->output, StreamId); /* StreamId */
|
||||
Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_ENDOFSTREAM); /* EventId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* cbData */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_started(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_playback_started(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
tsmf_presentation_start(presentation);
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 16);
|
||||
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* StreamId */
|
||||
Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_START_COMPLETED); /* EventId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* cbData */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_paused(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_playback_paused(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
/* Added pause control so gstreamer pipeline can be paused accordingly */
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
tsmf_presentation_paused(presentation);
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_restarted(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_playback_restarted(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
ifman->output_pending = TRUE;
|
||||
|
||||
/* Added restart control so gstreamer pipeline can be resumed accordingly */
|
||||
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
tsmf_presentation_restarted(presentation);
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_stopped(TSMF_IFMAN* ifman)
|
||||
int tsmf_ifman_on_playback_stopped(TSMF_IFMAN *ifman)
|
||||
{
|
||||
TSMF_PRESENTATION* presentation;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
TSMF_PRESENTATION *presentation;
|
||||
DEBUG_TSMF("");
|
||||
presentation = tsmf_presentation_find_by_id(Stream_Pointer(ifman->input));
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
tsmf_presentation_stop(presentation);
|
||||
else
|
||||
DEBUG_WARN("unknown presentation id");
|
||||
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 16);
|
||||
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* StreamId */
|
||||
Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_STOP_COMPLETED); /* EventId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* cbData */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN * ifman)
|
||||
int tsmf_ifman_on_playback_rate_changed(TSMF_IFMAN *ifman)
|
||||
{
|
||||
DEBUG_DVC("");
|
||||
|
||||
DEBUG_TSMF("");
|
||||
Stream_EnsureRemainingCapacity(ifman->output, 16);
|
||||
Stream_Write_UINT32(ifman->output, CLIENT_EVENT_NOTIFICATION); /* FunctionId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* StreamId */
|
||||
Stream_Write_UINT32(ifman->output, TSMM_CLIENT_EVENT_MONITORCHANGED); /* EventId */
|
||||
Stream_Write_UINT32(ifman->output, 0); /* cbData */
|
||||
ifman->output_interface_id = TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -47,19 +47,19 @@ struct _TSMF_LISTENER_CALLBACK
|
||||
{
|
||||
IWTSListenerCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
IWTSPlugin *plugin;
|
||||
IWTSVirtualChannelManager *channel_mgr;
|
||||
};
|
||||
|
||||
struct _TSMF_CHANNEL_CALLBACK
|
||||
{
|
||||
IWTSVirtualChannelCallback iface;
|
||||
|
||||
IWTSPlugin* plugin;
|
||||
IWTSVirtualChannelManager* channel_mgr;
|
||||
IWTSVirtualChannel* channel;
|
||||
IWTSPlugin *plugin;
|
||||
IWTSVirtualChannelManager *channel_mgr;
|
||||
IWTSVirtualChannel *channel;
|
||||
|
||||
BYTE presentation_id[16];
|
||||
BYTE presentation_id[GUID_SIZE];
|
||||
UINT32 stream_id;
|
||||
};
|
||||
|
||||
@ -67,20 +67,19 @@ struct _TSMF_PLUGIN
|
||||
{
|
||||
IWTSPlugin iface;
|
||||
|
||||
TSMF_LISTENER_CALLBACK* listener_callback;
|
||||
TSMF_LISTENER_CALLBACK *listener_callback;
|
||||
|
||||
const char* decoder_name;
|
||||
const char* audio_name;
|
||||
const char* audio_device;
|
||||
const char *decoder_name;
|
||||
const char *audio_name;
|
||||
const char *audio_device;
|
||||
};
|
||||
|
||||
void tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
UINT32 message_id, UINT64 duration, UINT32 data_size)
|
||||
void tsmf_playback_ack(IWTSVirtualChannelCallback *pChannelCallback,
|
||||
UINT32 message_id, UINT64 duration, UINT32 data_size)
|
||||
{
|
||||
wStream* s;
|
||||
int status;
|
||||
TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
wStream *s;
|
||||
int status = -1;
|
||||
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
|
||||
s = Stream_New(NULL, 32);
|
||||
Stream_Write_UINT32(s, TSMF_INTERFACE_CLIENT_NOTIFICATIONS | STREAM_ID_PROXY);
|
||||
Stream_Write_UINT32(s, message_id);
|
||||
@ -88,71 +87,66 @@ void tsmf_playback_ack(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
Stream_Write_UINT32(s, callback->stream_id); /* StreamId */
|
||||
Stream_Write_UINT64(s, duration); /* DataDuration */
|
||||
Stream_Write_UINT64(s, data_size); /* cbData */
|
||||
|
||||
DEBUG_DVC("response size %d", (int) Stream_GetPosition(s));
|
||||
status = callback->channel->Write(callback->channel, Stream_GetPosition(s), Stream_Buffer(s), NULL);
|
||||
|
||||
if (status)
|
||||
DEBUG_TSMF("response size %d", (int) Stream_GetPosition(s));
|
||||
if(!callback || !callback->channel || !callback->channel->Write)
|
||||
DEBUG_WARN("callback=%p, channel=%p, write=%p", callback,
|
||||
callback->channel, callback->channel->Write);
|
||||
else
|
||||
status = callback->channel->Write(callback->channel,
|
||||
Stream_GetPosition(s), Stream_Buffer(s), NULL);
|
||||
if(status)
|
||||
{
|
||||
DEBUG_WARN("response error %d", status);
|
||||
}
|
||||
|
||||
Stream_Free(s, TRUE);
|
||||
}
|
||||
|
||||
BOOL tsmf_push_event(IWTSVirtualChannelCallback* pChannelCallback, wMessage* event)
|
||||
BOOL tsmf_push_event(IWTSVirtualChannelCallback *pChannelCallback, wMessage *event)
|
||||
{
|
||||
int status;
|
||||
TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
|
||||
status = callback->channel_mgr->PushEvent(callback->channel_mgr, event);
|
||||
|
||||
if (status)
|
||||
if(status)
|
||||
{
|
||||
DEBUG_WARN("response error %d", status);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
UINT32 cbSize,
|
||||
BYTE* pBuffer)
|
||||
static int tsmf_on_data_received(IWTSVirtualChannelCallback *pChannelCallback,
|
||||
UINT32 cbSize,
|
||||
BYTE *pBuffer)
|
||||
{
|
||||
int length;
|
||||
wStream* input;
|
||||
wStream* output;
|
||||
wStream *input;
|
||||
wStream *output;
|
||||
int status = -1;
|
||||
TSMF_IFMAN ifman;
|
||||
UINT32 MessageId;
|
||||
UINT32 FunctionId;
|
||||
UINT32 InterfaceId;
|
||||
TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
|
||||
/* 2.2.1 Shared Message Header (SHARED_MSG_HEADER) */
|
||||
if (cbSize < 12)
|
||||
if(cbSize < 12)
|
||||
{
|
||||
DEBUG_WARN("invalid size. cbSize=%d", cbSize);
|
||||
return 1;
|
||||
}
|
||||
|
||||
input = Stream_New((BYTE*) pBuffer, cbSize);
|
||||
input = Stream_New((BYTE *) pBuffer, cbSize);
|
||||
output = Stream_New(NULL, 256);
|
||||
Stream_Seek(output, 8);
|
||||
|
||||
Stream_Read_UINT32(input, InterfaceId);
|
||||
Stream_Read_UINT32(input, MessageId);
|
||||
Stream_Read_UINT32(input, FunctionId);
|
||||
DEBUG_DVC("cbSize=%d InterfaceId=0x%X MessageId=0x%X FunctionId=0x%X",
|
||||
cbSize, InterfaceId, MessageId, FunctionId);
|
||||
|
||||
DEBUG_TSMF("cbSize=%d InterfaceId=0x%X MessageId=0x%X FunctionId=0x%X",
|
||||
cbSize, InterfaceId, MessageId, FunctionId);
|
||||
memset(&ifman, 0, sizeof(TSMF_IFMAN));
|
||||
ifman.channel_callback = pChannelCallback;
|
||||
ifman.decoder_name = ((TSMF_PLUGIN*) callback->plugin)->decoder_name;
|
||||
ifman.audio_name = ((TSMF_PLUGIN*) callback->plugin)->audio_name;
|
||||
ifman.audio_device = ((TSMF_PLUGIN*) callback->plugin)->audio_device;
|
||||
memcpy(ifman.presentation_id, callback->presentation_id, 16);
|
||||
ifman.decoder_name = ((TSMF_PLUGIN *) callback->plugin)->decoder_name;
|
||||
ifman.audio_name = ((TSMF_PLUGIN *) callback->plugin)->audio_name;
|
||||
ifman.audio_device = ((TSMF_PLUGIN *) callback->plugin)->audio_device;
|
||||
memcpy(ifman.presentation_id, callback->presentation_id, GUID_SIZE);
|
||||
ifman.stream_id = callback->stream_id;
|
||||
ifman.message_id = MessageId;
|
||||
ifman.input = input;
|
||||
@ -160,139 +154,108 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
ifman.output = output;
|
||||
ifman.output_pending = FALSE;
|
||||
ifman.output_interface_id = InterfaceId;
|
||||
|
||||
switch (InterfaceId)
|
||||
switch(InterfaceId)
|
||||
{
|
||||
case TSMF_INTERFACE_CAPABILITIES | STREAM_ID_NONE:
|
||||
|
||||
switch (FunctionId)
|
||||
switch(FunctionId)
|
||||
{
|
||||
case RIM_EXCHANGE_CAPABILITY_REQUEST:
|
||||
status = tsmf_ifman_rim_exchange_capability_request(&ifman);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case TSMF_INTERFACE_DEFAULT | STREAM_ID_PROXY:
|
||||
|
||||
switch (FunctionId)
|
||||
switch(FunctionId)
|
||||
{
|
||||
case SET_CHANNEL_PARAMS:
|
||||
memcpy(callback->presentation_id, Stream_Pointer(input), 16);
|
||||
Stream_Seek(input, 16);
|
||||
memcpy(callback->presentation_id, Stream_Pointer(input), GUID_SIZE);
|
||||
Stream_Seek(input, GUID_SIZE);
|
||||
Stream_Read_UINT32(input, callback->stream_id);
|
||||
DEBUG_DVC("SET_CHANNEL_PARAMS StreamId=%d", callback->stream_id);
|
||||
DEBUG_TSMF("SET_CHANNEL_PARAMS StreamId=%d", callback->stream_id);
|
||||
ifman.output_pending = TRUE;
|
||||
status = 0;
|
||||
break;
|
||||
|
||||
case EXCHANGE_CAPABILITIES_REQ:
|
||||
status = tsmf_ifman_exchange_capability_request(&ifman);
|
||||
break;
|
||||
|
||||
case CHECK_FORMAT_SUPPORT_REQ:
|
||||
status = tsmf_ifman_check_format_support_request(&ifman);
|
||||
break;
|
||||
|
||||
case ON_NEW_PRESENTATION:
|
||||
status = tsmf_ifman_on_new_presentation(&ifman);
|
||||
break;
|
||||
|
||||
case ADD_STREAM:
|
||||
status = tsmf_ifman_add_stream(&ifman);
|
||||
break;
|
||||
|
||||
case SET_TOPOLOGY_REQ:
|
||||
status = tsmf_ifman_set_topology_request(&ifman);
|
||||
break;
|
||||
|
||||
case REMOVE_STREAM:
|
||||
status = tsmf_ifman_remove_stream(&ifman);
|
||||
break;
|
||||
|
||||
case SET_SOURCE_VIDEO_RECT:
|
||||
status = tsmf_ifman_set_source_video_rect(&ifman);
|
||||
break;
|
||||
|
||||
case SHUTDOWN_PRESENTATION_REQ:
|
||||
status = tsmf_ifman_shutdown_presentation(&ifman);
|
||||
break;
|
||||
|
||||
case ON_STREAM_VOLUME:
|
||||
status = tsmf_ifman_on_stream_volume(&ifman);
|
||||
break;
|
||||
|
||||
case ON_CHANNEL_VOLUME:
|
||||
status = tsmf_ifman_on_channel_volume(&ifman);
|
||||
break;
|
||||
|
||||
case SET_VIDEO_WINDOW:
|
||||
status = tsmf_ifman_set_video_window(&ifman);
|
||||
break;
|
||||
|
||||
case UPDATE_GEOMETRY_INFO:
|
||||
status = tsmf_ifman_update_geometry_info(&ifman);
|
||||
break;
|
||||
|
||||
case SET_ALLOCATOR:
|
||||
status = tsmf_ifman_set_allocator(&ifman);
|
||||
break;
|
||||
|
||||
case NOTIFY_PREROLL:
|
||||
status = tsmf_ifman_notify_preroll(&ifman);
|
||||
break;
|
||||
|
||||
case ON_SAMPLE:
|
||||
status = tsmf_ifman_on_sample(&ifman);
|
||||
break;
|
||||
|
||||
case ON_FLUSH:
|
||||
status = tsmf_ifman_on_flush(&ifman);
|
||||
break;
|
||||
|
||||
case ON_END_OF_STREAM:
|
||||
status = tsmf_ifman_on_end_of_stream(&ifman);
|
||||
break;
|
||||
|
||||
case ON_PLAYBACK_STARTED:
|
||||
status = tsmf_ifman_on_playback_started(&ifman);
|
||||
break;
|
||||
|
||||
case ON_PLAYBACK_PAUSED:
|
||||
status = tsmf_ifman_on_playback_paused(&ifman);
|
||||
break;
|
||||
|
||||
case ON_PLAYBACK_RESTARTED:
|
||||
status = tsmf_ifman_on_playback_restarted(&ifman);
|
||||
break;
|
||||
|
||||
case ON_PLAYBACK_STOPPED:
|
||||
status = tsmf_ifman_on_playback_stopped(&ifman);
|
||||
break;
|
||||
|
||||
case ON_PLAYBACK_RATE_CHANGED:
|
||||
status = tsmf_ifman_on_playback_rate_changed(&ifman);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
Stream_Free(input, FALSE);
|
||||
input = NULL;
|
||||
ifman.input = NULL;
|
||||
|
||||
if (status == -1)
|
||||
if(status == -1)
|
||||
{
|
||||
switch (FunctionId)
|
||||
switch(FunctionId)
|
||||
{
|
||||
case RIMCALL_RELEASE:
|
||||
/* [MS-RDPEXPS] 2.2.2.2 Interface Release (IFACE_RELEASE)
|
||||
@ -300,121 +263,98 @@ static int tsmf_on_data_received(IWTSVirtualChannelCallback* pChannelCallback,
|
||||
status = 0;
|
||||
ifman.output_pending = 1;
|
||||
break;
|
||||
|
||||
case RIMCALL_QUERYINTERFACE:
|
||||
/* [MS-RDPEXPS] 2.2.2.1.2 Query Interface Response (QI_RSP)
|
||||
This message is not supported in this channel. */
|
||||
status = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (status == -1)
|
||||
if(status == -1)
|
||||
{
|
||||
DEBUG_WARN("InterfaceId 0x%X FunctionId 0x%X not processed.",
|
||||
InterfaceId, FunctionId);
|
||||
InterfaceId, FunctionId);
|
||||
/* When a request is not implemented we return empty response indicating error */
|
||||
}
|
||||
status = 0;
|
||||
}
|
||||
|
||||
if (status == 0 && !ifman.output_pending)
|
||||
if(status == 0 && !ifman.output_pending)
|
||||
{
|
||||
/* Response packet does not have FunctionId */
|
||||
length = Stream_GetPosition(output);
|
||||
Stream_SetPosition(output, 0);
|
||||
Stream_Write_UINT32(output, ifman.output_interface_id);
|
||||
Stream_Write_UINT32(output, MessageId);
|
||||
|
||||
DEBUG_DVC("response size %d", length);
|
||||
DEBUG_TSMF("response size %d", length);
|
||||
status = callback->channel->Write(callback->channel, length, Stream_Buffer(output), NULL);
|
||||
if (status)
|
||||
if(status)
|
||||
{
|
||||
DEBUG_WARN("response error %d", status);
|
||||
}
|
||||
}
|
||||
|
||||
Stream_Free(output, TRUE);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static int tsmf_on_close(IWTSVirtualChannelCallback* pChannelCallback)
|
||||
static int tsmf_on_close(IWTSVirtualChannelCallback *pChannelCallback)
|
||||
{
|
||||
TSMF_STREAM* stream;
|
||||
TSMF_PRESENTATION* presentation;
|
||||
TSMF_CHANNEL_CALLBACK* callback = (TSMF_CHANNEL_CALLBACK*) pChannelCallback;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
if (callback->stream_id)
|
||||
TSMF_STREAM *stream;
|
||||
TSMF_PRESENTATION *presentation;
|
||||
TSMF_CHANNEL_CALLBACK *callback = (TSMF_CHANNEL_CALLBACK *) pChannelCallback;
|
||||
DEBUG_TSMF("");
|
||||
if(callback->stream_id)
|
||||
{
|
||||
presentation = tsmf_presentation_find_by_id(callback->presentation_id);
|
||||
|
||||
if (presentation)
|
||||
if(presentation)
|
||||
{
|
||||
stream = tsmf_stream_find_by_id(presentation, callback->stream_id);
|
||||
|
||||
if (stream)
|
||||
if(stream)
|
||||
tsmf_stream_free(stream);
|
||||
}
|
||||
}
|
||||
|
||||
free(pChannelCallback);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tsmf_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
|
||||
IWTSVirtualChannel* pChannel,
|
||||
BYTE* Data,
|
||||
int* pbAccept,
|
||||
IWTSVirtualChannelCallback** ppCallback)
|
||||
static int tsmf_on_new_channel_connection(IWTSListenerCallback *pListenerCallback,
|
||||
IWTSVirtualChannel *pChannel,
|
||||
BYTE *Data,
|
||||
int *pbAccept,
|
||||
IWTSVirtualChannelCallback **ppCallback)
|
||||
{
|
||||
TSMF_CHANNEL_CALLBACK* callback;
|
||||
TSMF_LISTENER_CALLBACK* listener_callback = (TSMF_LISTENER_CALLBACK*) pListenerCallback;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
callback = (TSMF_CHANNEL_CALLBACK*) malloc(sizeof(TSMF_CHANNEL_CALLBACK));
|
||||
TSMF_CHANNEL_CALLBACK *callback;
|
||||
TSMF_LISTENER_CALLBACK *listener_callback = (TSMF_LISTENER_CALLBACK *) pListenerCallback;
|
||||
DEBUG_TSMF("");
|
||||
callback = (TSMF_CHANNEL_CALLBACK *) malloc(sizeof(TSMF_CHANNEL_CALLBACK));
|
||||
ZeroMemory(callback, sizeof(TSMF_CHANNEL_CALLBACK));
|
||||
|
||||
callback->iface.OnDataReceived = tsmf_on_data_received;
|
||||
callback->iface.OnClose = tsmf_on_close;
|
||||
callback->plugin = listener_callback->plugin;
|
||||
callback->channel_mgr = listener_callback->channel_mgr;
|
||||
callback->channel = pChannel;
|
||||
*ppCallback = (IWTSVirtualChannelCallback*) callback;
|
||||
|
||||
*ppCallback = (IWTSVirtualChannelCallback *) callback;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tsmf_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
|
||||
static int tsmf_plugin_initialize(IWTSPlugin *pPlugin, IWTSVirtualChannelManager *pChannelMgr)
|
||||
{
|
||||
TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
tsmf->listener_callback = (TSMF_LISTENER_CALLBACK*) malloc(sizeof(TSMF_LISTENER_CALLBACK));
|
||||
TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin;
|
||||
DEBUG_TSMF("");
|
||||
tsmf->listener_callback = (TSMF_LISTENER_CALLBACK *) malloc(sizeof(TSMF_LISTENER_CALLBACK));
|
||||
ZeroMemory(tsmf->listener_callback, sizeof(TSMF_LISTENER_CALLBACK));
|
||||
|
||||
tsmf->listener_callback->iface.OnNewChannelConnection = tsmf_on_new_channel_connection;
|
||||
tsmf->listener_callback->plugin = pPlugin;
|
||||
tsmf->listener_callback->channel_mgr = pChannelMgr;
|
||||
|
||||
return pChannelMgr->CreateListener(pChannelMgr, "TSMF", 0,
|
||||
(IWTSListenerCallback*) tsmf->listener_callback, NULL);
|
||||
(IWTSListenerCallback *) tsmf->listener_callback, NULL);
|
||||
}
|
||||
|
||||
static int tsmf_plugin_terminated(IWTSPlugin* pPlugin)
|
||||
static int tsmf_plugin_terminated(IWTSPlugin *pPlugin)
|
||||
{
|
||||
TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin;
|
||||
|
||||
DEBUG_DVC("");
|
||||
|
||||
if (tsmf->listener_callback)
|
||||
TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin;
|
||||
DEBUG_TSMF("");
|
||||
if(tsmf->listener_callback)
|
||||
free(tsmf->listener_callback);
|
||||
free(tsmf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -426,27 +366,21 @@ COMMAND_LINE_ARGUMENT_A tsmf_args[] =
|
||||
{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
|
||||
};
|
||||
|
||||
static void tsmf_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args)
|
||||
static void tsmf_process_addin_args(IWTSPlugin *pPlugin, ADDIN_ARGV *args)
|
||||
{
|
||||
int status;
|
||||
DWORD flags;
|
||||
COMMAND_LINE_ARGUMENT_A* arg;
|
||||
TSMF_PLUGIN* tsmf = (TSMF_PLUGIN*) pPlugin;
|
||||
|
||||
COMMAND_LINE_ARGUMENT_A *arg;
|
||||
TSMF_PLUGIN *tsmf = (TSMF_PLUGIN *) pPlugin;
|
||||
flags = COMMAND_LINE_SIGIL_NONE | COMMAND_LINE_SEPARATOR_COLON;
|
||||
|
||||
status = CommandLineParseArgumentsA(args->argc, (const char**) args->argv,
|
||||
tsmf_args, flags, tsmf, NULL, NULL);
|
||||
|
||||
status = CommandLineParseArgumentsA(args->argc, (const char **) args->argv,
|
||||
tsmf_args, flags, tsmf, NULL, NULL);
|
||||
arg = tsmf_args;
|
||||
|
||||
do
|
||||
{
|
||||
if (!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
|
||||
if(!(arg->Flags & COMMAND_LINE_VALUE_PRESENT))
|
||||
continue;
|
||||
|
||||
CommandLineSwitchStart(arg)
|
||||
|
||||
CommandLineSwitchCase(arg, "audio")
|
||||
{
|
||||
tsmf->audio_name = _strdup(arg->Value);
|
||||
@ -461,43 +395,35 @@ static void tsmf_process_addin_args(IWTSPlugin* pPlugin, ADDIN_ARGV* args)
|
||||
}
|
||||
CommandLineSwitchDefault(arg)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
CommandLineSwitchEnd(arg)
|
||||
}
|
||||
while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
|
||||
while((arg = CommandLineFindNextArgumentA(arg)) != NULL);
|
||||
}
|
||||
|
||||
#ifdef STATIC_CHANNELS
|
||||
#define DVCPluginEntry tsmf_DVCPluginEntry
|
||||
#endif
|
||||
|
||||
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
|
||||
int DVCPluginEntry(IDRDYNVC_ENTRY_POINTS *pEntryPoints)
|
||||
{
|
||||
int status = 0;
|
||||
TSMF_PLUGIN* tsmf;
|
||||
|
||||
tsmf = (TSMF_PLUGIN*) pEntryPoints->GetPlugin(pEntryPoints, "tsmf");
|
||||
|
||||
if (tsmf == NULL)
|
||||
TSMF_PLUGIN *tsmf;
|
||||
tsmf = (TSMF_PLUGIN *) pEntryPoints->GetPlugin(pEntryPoints, "tsmf");
|
||||
if(tsmf == NULL)
|
||||
{
|
||||
tsmf = (TSMF_PLUGIN*) malloc(sizeof(TSMF_PLUGIN));
|
||||
tsmf = (TSMF_PLUGIN *) malloc(sizeof(TSMF_PLUGIN));
|
||||
ZeroMemory(tsmf, sizeof(TSMF_PLUGIN));
|
||||
|
||||
tsmf->iface.Initialize = tsmf_plugin_initialize;
|
||||
tsmf->iface.Connected = NULL;
|
||||
tsmf->iface.Disconnected = NULL;
|
||||
tsmf->iface.Terminated = tsmf_plugin_terminated;
|
||||
status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", (IWTSPlugin*) tsmf);
|
||||
|
||||
status = pEntryPoints->RegisterPlugin(pEntryPoints, "tsmf", (IWTSPlugin *) tsmf);
|
||||
tsmf_media_init();
|
||||
}
|
||||
|
||||
if (status == 0)
|
||||
if(status == 0)
|
||||
{
|
||||
tsmf_process_addin_args((IWTSPlugin*) tsmf, pEntryPoints->GetPluginData(pEntryPoints));
|
||||
tsmf_process_addin_args((IWTSPlugin *) tsmf, pEntryPoints->GetPluginData(pEntryPoints));
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -32,30 +32,31 @@ typedef struct _TSMF_STREAM TSMF_STREAM;
|
||||
|
||||
typedef struct _TSMF_SAMPLE TSMF_SAMPLE;
|
||||
|
||||
TSMF_PRESENTATION* tsmf_presentation_new(const BYTE* guid, IWTSVirtualChannelCallback* pChannelCallback);
|
||||
TSMF_PRESENTATION* tsmf_presentation_find_by_id(const BYTE* 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);
|
||||
void tsmf_presentation_set_audio_device(TSMF_PRESENTATION* presentation,
|
||||
const char* name, const char* device);
|
||||
void tsmf_presentation_flush(TSMF_PRESENTATION* presentation);
|
||||
void tsmf_presentation_free(TSMF_PRESENTATION* presentation);
|
||||
TSMF_PRESENTATION *tsmf_presentation_new(const BYTE *guid, IWTSVirtualChannelCallback *pChannelCallback);
|
||||
TSMF_PRESENTATION *tsmf_presentation_find_by_id(const BYTE *guid);
|
||||
void tsmf_presentation_start(TSMF_PRESENTATION *presentation);
|
||||
void tsmf_presentation_stop(TSMF_PRESENTATION *presentation);
|
||||
void tsmf_presentation_sync(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);
|
||||
void tsmf_presentation_set_audio_device(TSMF_PRESENTATION *presentation,
|
||||
const char *name, const char *device);
|
||||
void tsmf_presentation_flush(TSMF_PRESENTATION *presentation);
|
||||
void tsmf_presentation_free(TSMF_PRESENTATION *presentation);
|
||||
|
||||
TSMF_STREAM* tsmf_stream_new(TSMF_PRESENTATION* presentation, UINT32 stream_id);
|
||||
TSMF_STREAM* tsmf_stream_find_by_id(TSMF_PRESENTATION* presentation, UINT32 stream_id);
|
||||
void tsmf_stream_set_format(TSMF_STREAM* stream, const char* name, wStream* s);
|
||||
void tsmf_stream_end(TSMF_STREAM* stream);
|
||||
void tsmf_stream_free(TSMF_STREAM* stream);
|
||||
TSMF_STREAM *tsmf_stream_new(TSMF_PRESENTATION *presentation, UINT32 stream_id);
|
||||
TSMF_STREAM *tsmf_stream_find_by_id(TSMF_PRESENTATION *presentation, UINT32 stream_id);
|
||||
void tsmf_stream_set_format(TSMF_STREAM *stream, const char *name, wStream *s);
|
||||
void tsmf_stream_end(TSMF_STREAM *stream);
|
||||
void tsmf_stream_free(TSMF_STREAM *stream);
|
||||
|
||||
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, BYTE* data);
|
||||
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, BYTE *data);
|
||||
|
||||
void tsmf_media_init(void);
|
||||
|
||||
|
@ -28,10 +28,10 @@
|
||||
#include <freerdp/types.h>
|
||||
#include <freerdp/utils/debug.h>
|
||||
|
||||
#ifdef WITH_DEBUG_DVC
|
||||
#define DEBUG_DVC(fmt, ...) DEBUG_CLASS(DVC, fmt, ## __VA_ARGS__)
|
||||
#ifdef WITH_DEBUG_TSMF
|
||||
#define DEBUG_TSMF(fmt, ...) DEBUG_CLASS(TSMF, fmt, ## __VA_ARGS__)
|
||||
#else
|
||||
#define DEBUG_DVC(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
||||
#define DEBUG_TSMF(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
typedef struct _TS_AM_MEDIA_TYPE
|
||||
@ -41,7 +41,7 @@ typedef struct _TS_AM_MEDIA_TYPE
|
||||
int FormatType;
|
||||
|
||||
UINT32 Width;
|
||||
UINT32 Height;
|
||||
UINT32 Height;
|
||||
UINT32 BitRate;
|
||||
struct
|
||||
{
|
||||
@ -51,7 +51,7 @@ typedef struct _TS_AM_MEDIA_TYPE
|
||||
UINT32 Channels;
|
||||
UINT32 BitsPerSample;
|
||||
UINT32 BlockAlign;
|
||||
const BYTE* ExtraData;
|
||||
const BYTE *ExtraData;
|
||||
UINT32 ExtraDataSize;
|
||||
} TS_AM_MEDIA_TYPE;
|
||||
|
||||
|
@ -9,33 +9,28 @@
|
||||
* the argument struct. */
|
||||
#include "../common/cmdline.c"
|
||||
|
||||
LPSTR tmp = NULL;
|
||||
|
||||
LPSTR tr_esc_str(LPCSTR arg)
|
||||
{
|
||||
LPSTR tmp = NULL;
|
||||
size_t cs = 0, x, ds;
|
||||
size_t s;
|
||||
|
||||
if( NULL == arg )
|
||||
if(NULL == arg)
|
||||
return NULL;
|
||||
|
||||
s = strlen(arg);
|
||||
|
||||
/* Find trailing whitespaces */
|
||||
while( (s > 0) && isspace(arg[s-1]))
|
||||
while((s > 0) && isspace(arg[s-1]))
|
||||
s--;
|
||||
|
||||
/* Prepare a initial buffer with the size of the result string. */
|
||||
if (s)
|
||||
tmp = (LPSTR)malloc(s * sizeof(CHAR));
|
||||
if( NULL == tmp )
|
||||
ds = s + 1;
|
||||
if(s)
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if(NULL == tmp)
|
||||
{
|
||||
fprintf(stderr, "Could not allocate string buffer.");
|
||||
exit(-2);
|
||||
}
|
||||
|
||||
/* Copy character for character and check, if it is necessary to escape. */
|
||||
ds = s + 1;
|
||||
memset(tmp, 0, ds * sizeof(CHAR));
|
||||
for(x=0; x<s; x++)
|
||||
{
|
||||
switch(arg[x])
|
||||
@ -43,7 +38,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
case '<':
|
||||
ds += 3;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if( NULL == tmp )
|
||||
if(NULL == tmp)
|
||||
{
|
||||
fprintf(stderr, "Could not reallocate string buffer.");
|
||||
exit(-3);
|
||||
@ -56,7 +51,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
case '>':
|
||||
ds += 3;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if( NULL == tmp )
|
||||
if(NULL == tmp)
|
||||
{
|
||||
fprintf(stderr, "Could not reallocate string buffer.");
|
||||
exit(-4);
|
||||
@ -69,7 +64,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
case '\'':
|
||||
ds += 5;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if( NULL == tmp )
|
||||
if(NULL == tmp)
|
||||
{
|
||||
fprintf(stderr, "Could not reallocate string buffer.");
|
||||
exit(-5);
|
||||
@ -84,7 +79,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
case '"':
|
||||
ds += 5;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if( NULL == tmp )
|
||||
if(NULL == tmp)
|
||||
{
|
||||
fprintf(stderr, "Could not reallocate string buffer.");
|
||||
exit(-6);
|
||||
@ -99,7 +94,7 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
case '&':
|
||||
ds += 4;
|
||||
tmp = (LPSTR)realloc(tmp, ds * sizeof(CHAR));
|
||||
if( NULL == tmp )
|
||||
if(NULL == tmp)
|
||||
{
|
||||
fprintf(stderr, "Could not reallocate string buffer.");
|
||||
exit(-7);
|
||||
@ -114,11 +109,9 @@ LPSTR tr_esc_str(LPCSTR arg)
|
||||
tmp[cs++] = arg[x];
|
||||
break;
|
||||
}
|
||||
|
||||
/* Assure, the string is '\0' terminated. */
|
||||
tmp[ds-1] = '\0';
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
@ -128,51 +121,46 @@ int main(int argc, char *argv[])
|
||||
size_t x;
|
||||
const char *fname = "xfreerdp-argument.1.xml";
|
||||
FILE *fp = NULL;
|
||||
|
||||
/* Open output file for writing, truncate if existing. */
|
||||
fp = fopen(fname, "w");
|
||||
if( NULL == fp )
|
||||
if(NULL == fp)
|
||||
{
|
||||
fprintf(stderr, "Could not open '%s' for writing.", fname);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* The tag used as header in the manpage */
|
||||
fprintf(fp, "<refsect1>\n");
|
||||
fprintf(fp, "\t<title>Options</title>\n");
|
||||
fprintf(fp, "\t\t<variablelist>\n");
|
||||
|
||||
/* Iterate over argument struct and write data to docbook 4.5
|
||||
/* Iterate over argument struct and write data to docbook 4.5
|
||||
* compatible XML */
|
||||
if( elements < 2 )
|
||||
if(elements < 2)
|
||||
{
|
||||
fprintf(stderr, "The argument array 'args' is empty, writing an empty file.");
|
||||
elements = 1;
|
||||
}
|
||||
|
||||
for(x=0; x<elements - 1; x++)
|
||||
{
|
||||
const COMMAND_LINE_ARGUMENT_A *arg = &args[x];
|
||||
|
||||
const char *name = tr_esc_str((LPSTR) arg->Name);
|
||||
const char *format = tr_esc_str(arg->Format);
|
||||
const char *text = tr_esc_str((LPSTR) arg->Text);
|
||||
fprintf(fp, "\t\t\t<varlistentry>\n");
|
||||
if ( COMMAND_LINE_VALUE_REQUIRED == arg->Flags)
|
||||
fprintf(fp, "\t\t\t\t<term><option>/%s</option> <replaceable>%s</replaceable></term>\n", tr_esc_str((LPSTR) arg->Name), tr_esc_str(arg->Format) );
|
||||
if(COMMAND_LINE_VALUE_REQUIRED == arg->Flags)
|
||||
fprintf(fp, "\t\t\t\t<term><option>/%s</option> <replaceable>%s</replaceable></term>\n", name, format);
|
||||
else
|
||||
fprintf(fp, "\t\t\t\t<term><option>/%s</option></term>\n", tr_esc_str((LPSTR) arg->Name));
|
||||
fprintf(fp, "\t\t\t\t<term><option>/%s</option></term>\n", name);
|
||||
fprintf(fp, "\t\t\t\t<listitem>\n");
|
||||
fprintf(fp, "\t\t\t\t\t<para>%s</para>\n", tr_esc_str((LPSTR) arg->Text));
|
||||
|
||||
fprintf(fp, "\t\t\t\t\t<para>%s</para>\n", format);
|
||||
fprintf(fp, "\t\t\t\t</listitem>\n");
|
||||
fprintf(fp, "\t\t\t</varlistentry>\n");
|
||||
free(name);
|
||||
free(format);
|
||||
free(text);
|
||||
}
|
||||
|
||||
fprintf(fp, "\t\t</variablelist>\n");
|
||||
fprintf(fp, "\t</refsect1>\n");
|
||||
fclose(fp);
|
||||
|
||||
if(NULL != tmp)
|
||||
free(tmp);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -71,10 +71,12 @@ struct xf_window
|
||||
int bottom;
|
||||
int width;
|
||||
int height;
|
||||
int shmid;
|
||||
Window handle;
|
||||
Window *xfwin;
|
||||
BOOL fullscreen;
|
||||
BOOL decorations;
|
||||
rdpWindow* window;
|
||||
rdpWindow *window;
|
||||
BOOL is_mapped;
|
||||
BOOL is_transient;
|
||||
xfLocalMove local_move;
|
||||
@ -82,39 +84,39 @@ struct xf_window
|
||||
BOOL rail_ignore_configure;
|
||||
};
|
||||
|
||||
void xf_ewmhints_init(xfContext* xfc);
|
||||
void xf_ewmhints_init(xfContext *xfc);
|
||||
|
||||
BOOL xf_GetCurrentDesktop(xfContext* xfc);
|
||||
BOOL xf_GetWorkArea(xfContext* xfc);
|
||||
BOOL xf_GetCurrentDesktop(xfContext *xfc);
|
||||
BOOL xf_GetWorkArea(xfContext *xfc);
|
||||
|
||||
void xf_SetWindowFullscreen(xfContext* xfc, xfWindow* window, BOOL fullscreen);
|
||||
void xf_SetWindowDecorations(xfContext* xfc, xfWindow* window, BOOL show);
|
||||
void xf_SetWindowUnlisted(xfContext* xfc, xfWindow* window);
|
||||
void xf_SetWindowFullscreen(xfContext *xfc, xfWindow *window, BOOL fullscreen);
|
||||
void xf_SetWindowDecorations(xfContext *xfc, xfWindow *window, BOOL show);
|
||||
void xf_SetWindowUnlisted(xfContext *xfc, xfWindow *window);
|
||||
|
||||
xfWindow* xf_CreateDesktopWindow(xfContext* xfc, char* name, int width, int height, BOOL decorations);
|
||||
void xf_ResizeDesktopWindow(xfContext* xfc, xfWindow* window, int width, int height);
|
||||
xfWindow *xf_CreateDesktopWindow(xfContext *xfc, char *name, int width, int height, BOOL decorations);
|
||||
void xf_ResizeDesktopWindow(xfContext *xfc, xfWindow *window, int width, int height);
|
||||
|
||||
xfWindow* xf_CreateWindow(xfContext* xfc, rdpWindow* wnd, int x, int y, int width, int height, UINT32 id);
|
||||
void xf_SetWindowText(xfContext* xfc, xfWindow* window, char *name);
|
||||
void xf_MoveWindow(xfContext* xfc, xfWindow* window, int x, int y, int width, int height);
|
||||
void xf_ShowWindow(xfContext* xfc, xfWindow* window, BYTE state);
|
||||
void xf_SetWindowIcon(xfContext* xfc, xfWindow* window, rdpIcon* icon);
|
||||
void xf_SetWindowRects(xfContext* xfc, xfWindow* window, RECTANGLE_16* rects, int nrects);
|
||||
void xf_SetWindowVisibilityRects(xfContext* xfc, xfWindow* window, RECTANGLE_16* rects, int nrects);
|
||||
void xf_SetWindowStyle(xfContext* xfc, xfWindow* window, UINT32 style, UINT32 ex_style);
|
||||
void xf_UpdateWindowArea(xfContext* xfc, xfWindow* window, int x, int y, int width, int height);
|
||||
BOOL xf_IsWindowBorder(xfContext* xfc, xfWindow* xfw, int x, int y);
|
||||
void xf_DestroyWindow(xfContext* xfc, xfWindow* window);
|
||||
rdpWindow* xf_rdpWindowFromWindow(xfContext* xfc, Window wnd);
|
||||
xfWindow *xf_CreateWindow(xfContext *xfc, rdpWindow *wnd, int x, int y, int width, int height, UINT32 id);
|
||||
void xf_SetWindowText(xfContext *xfc, xfWindow *window, char *name);
|
||||
void xf_MoveWindow(xfContext *xfc, xfWindow *window, int x, int y, int width, int height);
|
||||
void xf_ShowWindow(xfContext *xfc, xfWindow *window, BYTE state);
|
||||
void xf_SetWindowIcon(xfContext *xfc, xfWindow *window, rdpIcon *icon);
|
||||
void xf_SetWindowRects(xfContext *xfc, xfWindow *window, RECTANGLE_16 *rects, int nrects);
|
||||
void xf_SetWindowVisibilityRects(xfContext *xfc, xfWindow *window, RECTANGLE_16 *rects, int nrects);
|
||||
void xf_SetWindowStyle(xfContext *xfc, xfWindow *window, UINT32 style, UINT32 ex_style);
|
||||
void xf_UpdateWindowArea(xfContext *xfc, xfWindow *window, int x, int y, int width, int height);
|
||||
BOOL xf_IsWindowBorder(xfContext *xfc, xfWindow *xfw, int x, int y);
|
||||
void xf_DestroyWindow(xfContext *xfc, xfWindow *window);
|
||||
rdpWindow *xf_rdpWindowFromWindow(xfContext *xfc, Window wnd);
|
||||
|
||||
BOOL xf_GetWindowProperty(xfContext* xfc, Window window, Atom property, int length,
|
||||
unsigned long* nitems, unsigned long* bytes, BYTE** prop);
|
||||
BOOL xf_GetWindowProperty(xfContext *xfc, Window window, Atom property, int length,
|
||||
unsigned long *nitems, unsigned long *bytes, BYTE **prop);
|
||||
|
||||
void xf_SetWindowMinMaxInfo(xfContext* xfc, xfWindow* window, int maxWidth, int maxHeight,
|
||||
int maxPosX, int maxPosY, int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight);
|
||||
void xf_SetWindowMinMaxInfo(xfContext *xfc, xfWindow *window, int maxWidth, int maxHeight,
|
||||
int maxPosX, int maxPosY, int minTrackWidth, int minTrackHeight, int maxTrackWidth, int maxTrackHeight);
|
||||
|
||||
void xf_StartLocalMoveSize(xfContext* xfc, xfWindow* window, int direction, int x, int y);
|
||||
void xf_EndLocalMoveSize(xfContext* xfc, xfWindow *window);
|
||||
void xf_SendClientEvent(xfContext* xfc, xfWindow* window, Atom atom, unsigned int numArgs, ...);
|
||||
void xf_StartLocalMoveSize(xfContext *xfc, xfWindow *window, int direction, int x, int y);
|
||||
void xf_EndLocalMoveSize(xfContext *xfc, xfWindow *window);
|
||||
void xf_SendClientEvent(xfContext *xfc, xfWindow *window, Atom atom, unsigned int numArgs, ...);
|
||||
|
||||
#endif /* __XF_WINDOW_H */
|
||||
|
@ -814,6 +814,38 @@ int freerdp_parse_username(char* username, char** user, char** domain)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int freerdp_parse_hostname(char* hostname, char** host, int* port)
|
||||
{
|
||||
char* p;
|
||||
int length;
|
||||
|
||||
p = strrchr(hostname, ':');
|
||||
|
||||
if (p)
|
||||
{
|
||||
length = (p - hostname);
|
||||
*host = (char*) malloc(length + 1);
|
||||
|
||||
if (!(*host))
|
||||
return -1;
|
||||
|
||||
CopyMemory(*host, hostname, length);
|
||||
(*host)[length] = '\0';
|
||||
*port = atoi(p + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
*host = _strdup(hostname);
|
||||
|
||||
if (!(*host))
|
||||
return -1;
|
||||
|
||||
*port = -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int freerdp_set_connection_type(rdpSettings* settings, int type)
|
||||
{
|
||||
settings->ConnectionType = type;
|
||||
|
@ -767,10 +767,23 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
|
||||
free(domain);
|
||||
}
|
||||
|
||||
if (~((size_t) file->FullAddress))
|
||||
{
|
||||
int port = -1;
|
||||
char* host = NULL;
|
||||
|
||||
freerdp_parse_hostname(file->FullAddress, &host, &port);
|
||||
|
||||
freerdp_set_param_string(settings, FreeRDP_ServerHostname, host);
|
||||
|
||||
if (port > 0)
|
||||
freerdp_set_param_uint32(settings, FreeRDP_ServerPort, (UINT32) port);
|
||||
|
||||
free(host);
|
||||
}
|
||||
|
||||
if (~file->ServerPort)
|
||||
freerdp_set_param_uint32(settings, FreeRDP_ServerPort, file->ServerPort);
|
||||
if (~((size_t) file->FullAddress))
|
||||
freerdp_set_param_string(settings, FreeRDP_ServerHostname, file->FullAddress);
|
||||
|
||||
if (~file->DesktopWidth)
|
||||
freerdp_set_param_uint32(settings, FreeRDP_DesktopWidth, file->DesktopWidth);
|
||||
@ -867,7 +880,19 @@ BOOL freerdp_client_populate_settings_from_rdp_file(rdpFile* file, rdpSettings*
|
||||
freerdp_set_param_bool(settings, FreeRDP_CompressionEnabled, file->Compression);
|
||||
|
||||
if (~((size_t) file->GatewayHostname))
|
||||
freerdp_set_param_string(settings, FreeRDP_GatewayHostname, file->GatewayHostname);
|
||||
{
|
||||
int port = -1;
|
||||
char* host = NULL;
|
||||
|
||||
freerdp_parse_hostname(file->GatewayHostname, &host, &port);
|
||||
|
||||
freerdp_set_param_string(settings, FreeRDP_GatewayHostname, host);
|
||||
|
||||
if (port > 0)
|
||||
freerdp_set_param_uint32(settings, FreeRDP_GatewayPort, (UINT32) port);
|
||||
|
||||
free(host);
|
||||
}
|
||||
|
||||
if (~file->GatewayUsageMethod)
|
||||
freerdp_set_gateway_usage_method(settings, file->GatewayUsageMethod);
|
||||
|
@ -100,6 +100,7 @@ option(WITH_DEBUG_CAPABILITIES "Print capability negotiation debug messages." ${
|
||||
option(WITH_DEBUG_CHANNELS "Print channel manager debug messages." ${DEFAULT_DEBUG_OPTION})
|
||||
option(WITH_DEBUG_CLIPRDR "Print clipboard redirection debug messages" ${DEFAULT_DEBUG_OPTION})
|
||||
option(WITH_DEBUG_DVC "Print dynamic virtual channel debug messages." ${DEFAULT_DEBUG_OPTION})
|
||||
option(WITH_DEBUG_TSMF "Print TSMF virtual channel debug messages." ${DEFAULT_DEBUG_OPTION})
|
||||
option(WITH_DEBUG_GDI "Print graphics debug messages." ${DEFAULT_DEBUG_OPTION})
|
||||
option(WITH_DEBUG_KBD "Print keyboard related debug messages." ${DEFAULT_DEBUG_OPTION})
|
||||
option(WITH_DEBUG_LICENSE "Print license debug messages." ${DEFAULT_DEBUG_OPTION})
|
||||
|
118
cmake/FindGStreamer_0_10.cmake
Normal file
118
cmake/FindGStreamer_0_10.cmake
Normal file
@ -0,0 +1,118 @@
|
||||
# - Try to find GStreamer
|
||||
# Once done this will define
|
||||
#
|
||||
# GSTREAMER_0_10_FOUND - system has GStreamer
|
||||
# GSTREAMER_0_10_INCLUDE_DIRS - the GStreamer include directory
|
||||
# GSTREAMER_0_10_LIBRARIES - the libraries needed to use GStreamer
|
||||
# GSTREAMER_0_10_DEFINITIONS - Compiler switches required for using GStreamer
|
||||
|
||||
# Copyright (c) 2006, Tim Beaulen <tbscope@gmail.com>
|
||||
#
|
||||
# Redistribution and use is allowed according to the terms of the BSD license.
|
||||
# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
|
||||
|
||||
# TODO: Other versions --> GSTREAMER_X_Y_FOUND (Example: GSTREAMER_0_8_FOUND and GSTREAMER_0_10_FOUND etc)
|
||||
|
||||
IF (GSTREAMER_0_10_INCLUDE_DIRS AND GSTREAMER_0_10_LIBRARIES AND GSTREAMER_0_10_BASE_LIBRARY AND GSTREAMER_0_10_INTERFACE_LIBRARY)
|
||||
# in cache already
|
||||
SET(GSTREAMER_0_10_FIND_QUIETLY TRUE)
|
||||
ELSE (GSTREAMER_0_10_INCLUDE_DIRS AND GSTREAMER_0_10_LIBRARIES AND GSTREAMER_0_10_BASE_LIBRARY AND GSTREAMER_0_10_INTERFACE_LIBRARY)
|
||||
SET(GSTREAMER_0_10_FIND_QUIETLY FALSE)
|
||||
ENDIF (GSTREAMER_0_10_INCLUDE_DIRS AND GSTREAMER_0_10_LIBRARIES AND GSTREAMER_0_10_BASE_LIBRARY AND GSTREAMER_0_10_INTERFACE_LIBRARY)
|
||||
|
||||
IF (NOT WIN32)
|
||||
# use pkg-config to get the directories and then use these values
|
||||
# in the FIND_PATH() and FIND_LIBRARY() calls
|
||||
FIND_PACKAGE(PkgConfig)
|
||||
PKG_CHECK_MODULES(PC_GSTREAMER_0_10 QUIET gstreamer-0.10)
|
||||
#MESSAGE(STATUS "DEBUG: GStreamer include directory = ${GSTREAMER_0_10_INCLUDE_DIRSS}")
|
||||
#MESSAGE(STATUS "DEBUG: GStreamer link directory = ${GSTREAMER_0_10_LIBRARY_DIRS}")
|
||||
#MESSAGE(STATUS "DEBUG: GStreamer CFlags = ${GSTREAMER_0_10_CFLAGS_OTHER}")
|
||||
SET(GSTREAMER_0_10_DEFINITIONS ${PC_GSTREAMER_0_10_CFLAGS_OTHER})
|
||||
ENDIF (NOT WIN32)
|
||||
|
||||
FIND_PATH(GSTREAMER_0_10_INCLUDE_DIRS gst/gst.h
|
||||
PATHS
|
||||
${PC_GSTREAMER_0_10_INCLUDEDIR}
|
||||
${PC_GSTREAMER_0_10_INCLUDE_DIRSS}
|
||||
#PATH_SUFFIXES gst
|
||||
)
|
||||
|
||||
FIND_LIBRARY(GSTREAMER_0_10_LIBRARIES NAMES gstreamer-0.10
|
||||
PATHS
|
||||
${PC_GSTREAMER_0_10_LIBDIR}
|
||||
${PC_GSTREAMER_0_10_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
FIND_LIBRARY(GSTREAMER_0_10_BASE_LIBRARY NAMES gstbase-0.10
|
||||
PATHS
|
||||
${PC_GSTREAMER_0_10_LIBDIR}
|
||||
${PC_GSTREAMER_0_10_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
FIND_LIBRARY(GSTREAMER_0_10_APP_LIBRARY NAMES gstapp-0.10
|
||||
PATHS
|
||||
${PC_GSTREAMER_0_10_LIBDIR}
|
||||
${PC_GSTREAMER_0_10_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
FIND_LIBRARY(GSTREAMER_0_10_INTERFACE_LIBRARY NAMES gstinterfaces-0.10
|
||||
PATHS
|
||||
${PC_GSTREAMER_0_10_LIBDIR}
|
||||
${PC_GSTREAMER_0_10_LIBRARY_DIRS}
|
||||
)
|
||||
|
||||
FIND_PACKAGE(Glib REQUIRED)
|
||||
FIND_PACKAGE(LibXml2 REQUIRED)
|
||||
|
||||
IF (GSTREAMER_0_10_INCLUDE_DIRS)
|
||||
#MESSAGE(STATUS "DEBUG: Found GStreamer include dir: ${GSTREAMER_0_10_INCLUDE_DIRS}")
|
||||
ELSE (GSTREAMER_0_10_INCLUDE_DIRS)
|
||||
MESSAGE(STATUS "GStreamer: WARNING: include dir not found")
|
||||
ENDIF (GSTREAMER_0_10_INCLUDE_DIRS)
|
||||
|
||||
IF (GSTREAMER_0_10_LIBRARIES)
|
||||
#MESSAGE(STATUS "DEBUG: Found GStreamer library: ${GSTREAMER_0_10_LIBRARIES}")
|
||||
ELSE (GSTREAMER_0_10_LIBRARIES)
|
||||
MESSAGE(STATUS "GStreamer: WARNING: library not found")
|
||||
ENDIF (GSTREAMER_0_10_LIBRARIES)
|
||||
|
||||
IF (GSTREAMER_0_10_INTERFACE_LIBRARY)
|
||||
#MESSAGE(STATUS "DEBUG: Found GStreamer interface library: ${GSTREAMER_0_10_INTERFACE_LIBRARY}")
|
||||
ELSE (GSTREAMER_0_10_INTERFACE_LIBRARY)
|
||||
MESSAGE(STATUS "GStreamer: WARNING: interface library not found")
|
||||
ENDIF (GSTREAMER_0_10_INTERFACE_LIBRARY)
|
||||
|
||||
set(_GSTREAMER_0_10_REQUIRED_VARS
|
||||
Glib_INCLUDE_DIRS
|
||||
Glib_LIBRARIES
|
||||
LIBXML2_INCLUDE_DIR
|
||||
LIBXML2_LIBRARIES
|
||||
GSTREAMER_0_10_INCLUDE_DIRS
|
||||
GSTREAMER_0_10_LIBRARIES
|
||||
VERSION_OK
|
||||
GSTREAMER_0_10_BASE_INCLUDE_DIRS
|
||||
GSTREAMER_0_10_BASE_LIBRARY
|
||||
GSTREAMER_0_10_INTERFACE_INCLUDE_DIRS
|
||||
GSTREAMER_0_10_INTERFACE_LIBRARY)
|
||||
|
||||
INCLUDE(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GSTREAMER_0_10 DEFAULT_MSG
|
||||
GSTREAMER_0_10_LIBRARIES
|
||||
GSTREAMER_0_10_INCLUDE_DIRS
|
||||
GSTREAMER_0_10_BASE_LIBRARY
|
||||
GSTREAMER_0_10_INTERFACE_LIBRARY)
|
||||
|
||||
list(APPEND GSTREAMER_0_10_INCLUDE_DIRS ${Glib_INCLUDE_DIRS})
|
||||
list(APPEND GSTREAMER_0_10_LIBRARIES ${Glib_LIBRARIES})
|
||||
list(APPEND GSTREAMER_0_10_INCLUDE_DIRS ${LIBXML2_INCLUDE_DIR})
|
||||
list(APPEND GSTREAMER_0_10_LIBRARIES ${LIBXML2_LIBRARIES})
|
||||
list(APPEND GSTREAMER_0_10_INCLUDE_DIRS ${GSTREAMER_0_10_BASE_INCLUDE_DIR})
|
||||
list(APPEND GSTREAMER_0_10_LIBRARIES ${GSTREAMER_0_10_BASE_LIBRARY})
|
||||
list(APPEND GSTREAMER_0_10_INCLUDE_DIRS ${GSTREAMER_0_10_APP_INCLUDE_DIR})
|
||||
list(APPEND GSTREAMER_0_10_LIBRARIES ${GSTREAMER_0_10_APP_LIBRARY})
|
||||
list(APPEND GSTREAMER_0_10_INCLUDE_DIRS ${GSTREAMER_0_10_INTERFACE_INCLUDE_DIR})
|
||||
list(APPEND GSTREAMER_0_10_LIBRARIES ${GSTREAMER_0_10_INTERFACE_LIBRARY})
|
||||
|
||||
MARK_AS_ADVANCED(GSTREAMER_0_10_INCLUDE_DIRS GSTREAMER_0_10_LIBRARIES GSTREAMER_0_10_BASE_LIBRARY GSTREAMER_0_10_INTERFACE_LIBRARY)
|
||||
|
153
cmake/FindGStreamer_1_0.cmake
Normal file
153
cmake/FindGStreamer_1_0.cmake
Normal file
@ -0,0 +1,153 @@
|
||||
# - Try to find Gstreamer and its plugins
|
||||
# Once done, this will define
|
||||
#
|
||||
# GSTREAMER_1_0_FOUND - system has Gstreamer
|
||||
# GSTREAMER_1_0_INCLUDE_DIRS - the Gstreamer include directories
|
||||
# GSTREAMER_1_0_LIBRARIES - link these to use Gstreamer
|
||||
#
|
||||
# Additionally, gstreamer-base is always looked for and required, and
|
||||
# the following related variables are defined:
|
||||
#
|
||||
# GSTREAMER_1_0_BASE_INCLUDE_DIRS - gstreamer-base's include directory
|
||||
# GSTREAMER_1_0_BASE_LIBRARIES - link to these to use gstreamer-base
|
||||
#
|
||||
# Optionally, the COMPONENTS keyword can be passed to find_package()
|
||||
# and Gstreamer plugins can be looked for. Currently, the following
|
||||
# plugins can be searched, and they define the following variables if
|
||||
# found:
|
||||
#
|
||||
# gstreamer-app: GSTREAMER_1_0_APP_INCLUDE_DIRS and GSTREAMER_1_0_APP_LIBRARIES
|
||||
# gstreamer-audio: GSTREAMER_1_0_AUDIO_INCLUDE_DIRS and GSTREAMER_1_0_AUDIO_LIBRARIES
|
||||
# gstreamer-fft: GSTREAMER_1_0_FFT_INCLUDE_DIRS and GSTREAMER_1_0_FFT_LIBRARIES
|
||||
# gstreamer-pbutils: GSTREAMER_1_0_PBUTILS_INCLUDE_DIRS and GSTREAMER_1_0_PBUTILS_LIBRARIES
|
||||
# gstreamer-video: GSTREAMER_1_0_VIDEO_INCLUDE_DIRS and GSTREAMER_1_0_VIDEO_LIBRARIES
|
||||
#
|
||||
# Copyright (C) 2012 Raphael Kubo da Costa <rakuco@webkit.org>
|
||||
#
|
||||
# Redistribution and use in source and binary forms, with or without
|
||||
# modification, are permitted provided that the following conditions
|
||||
# are met:
|
||||
# 1. Redistributions of source code must retain the above copyright
|
||||
# notice, this list of conditions and the following disclaimer.
|
||||
# 2. Redistributions in binary form must reproduce the above copyright
|
||||
# notice, this list of conditions and the following disclaimer in the
|
||||
# documentation and/or other materials provided with the distribution.
|
||||
#
|
||||
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND ITS CONTRIBUTORS ``AS
|
||||
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR ITS
|
||||
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
||||
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||
# OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||
# WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||
# OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||
# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
||||
# The minimum Gstreamer version we support.
|
||||
set(GSTREAMER_1_0_MINIMUM_VERSION 1.0.5)
|
||||
|
||||
# Helper macro to find a Gstreamer plugin (or Gstreamer itself)
|
||||
# _component_prefix is prepended to the _INCLUDE_DIRS and _LIBRARIES variables (eg. "GSTREAMER_1_0_AUDIO")
|
||||
# _pkgconfig_name is the component's pkg-config name (eg. "gstreamer-1.0", or "gstreamer-video-1.0").
|
||||
# _header is the component's header, relative to the gstreamer-1.0 directory (eg. "gst/gst.h").
|
||||
# _library is the component's library name (eg. "gstreamer-1.0" or "gstvideo-1.0")
|
||||
macro(FIND_GSTREAMER_COMPONENT _component_prefix _pkgconfig_name _header _library)
|
||||
# FIXME: The QUIET keyword can be used once we require CMake 2.8.2.
|
||||
pkg_check_modules(PC_${_component_prefix} ${_pkgconfig_name})
|
||||
|
||||
find_path(${_component_prefix}_INCLUDE_DIRS
|
||||
NAMES ${_header}
|
||||
HINTS ${PC_${_component_prefix}_INCLUDE_DIRS} ${PC_${_component_prefix}_INCLUDEDIR}
|
||||
PATH_SUFFIXES gstreamer-1.0
|
||||
)
|
||||
|
||||
find_library(${_component_prefix}_LIBRARIES
|
||||
NAMES ${_library} gstreamer_android
|
||||
HINTS ${PC_${_component_prefix}_LIBRARY_DIRS} ${PC_${_component_prefix}_LIBDIR} ${GSTREAMER_1_0_ROOT_DIR}
|
||||
)
|
||||
endmacro()
|
||||
|
||||
# ------------------------
|
||||
# 1. Find Gstreamer itself
|
||||
# ------------------------
|
||||
|
||||
# 1.1. Find headers and libraries
|
||||
set(GLIB_ROOT_DIR ${GSTREAMER_1_0_ROOT_DIR})
|
||||
find_package(Glib REQUIRED)
|
||||
FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0 gstreamer-1.0 gst/gst.h gstreamer-1.0)
|
||||
FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0_BASE gstreamer-base-1.0 gst/gst.h gstbase-1.0)
|
||||
|
||||
# 1.2. Check Gstreamer version
|
||||
if (GSTREAMER_1_0_INCLUDE_DIRS)
|
||||
if (EXISTS "${GSTREAMER_1_0_INCLUDE_DIRS}/gst/gstversion.h")
|
||||
file(READ "${GSTREAMER_1_0_INCLUDE_DIRS}/gst/gstversion.h" GSTREAMER_VERSION_CONTENTS)
|
||||
|
||||
string(REGEX MATCH "#define +GST_VERSION_MAJOR +\\(([0-9]+)\\)" _dummy "${GSTREAMER_VERSION_CONTENTS}")
|
||||
set(GSTREAMER_1_0_VERSION_MAJOR "${CMAKE_MATCH_1}")
|
||||
|
||||
string(REGEX MATCH "#define +GST_VERSION_MINOR +\\(([0-9]+)\\)" _dummy "${GSTREAMER_1_0_VERSION_CONTENTS}")
|
||||
set(GSTREAMER_1_0_VERSION_MINOR "${CMAKE_MATCH_1}")
|
||||
|
||||
string(REGEX MATCH "#define +GST_VERSION_MICRO +\\(([0-9]+)\\)" _dummy "${GSTREAMER_1_0_VERSION_CONTENTS}")
|
||||
set(GSTREAMER_1_0_VERSION_MICRO "${CMAKE_MATCH_1}")
|
||||
|
||||
set(GSTREAMER_1_0_VERSION "${GSTREAMER_1_0_VERSION_MAJOR}.${GSTREAMER_1_0_VERSION_MINOR}.${GSTREAMER_1_0_VERSION_MICRO}")
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# FIXME: With CMake 2.8.3 we can just pass GSTREAMER_1_0_VERSION to FIND_PACKAGE_HANDLE_STANDARD_ARGS as VERSION_VAR
|
||||
# and remove the version check here (GSTREAMER_1_0_MINIMUM_VERSION would be passed to FIND_PACKAGE).
|
||||
set(VERSION_OK TRUE)
|
||||
if ("${GSTREAMER_1_0_VERSION}" VERSION_LESS "${GSTREAMER_1_0_MINIMUM_VERSION}")
|
||||
set(VERSION_OK FALSE)
|
||||
endif ()
|
||||
|
||||
# -------------------------
|
||||
# 2. Find Gstreamer plugins
|
||||
# -------------------------
|
||||
|
||||
FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0_APP gstreamer-app-1.0 gst/app/gstappsink.h gstapp-1.0)
|
||||
FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0_AUDIO gstreamer-audio-1.0 gst/audio/audio.h gstaudio-1.0)
|
||||
FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0_FFT gstreamer-fft-1.0 gst/fft/gstfft.h gstfft-1.0)
|
||||
FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0_PBUTILS gstreamer-pbutils-1.0 gst/pbutils/pbutils.h gstpbutils-1.0)
|
||||
FIND_GSTREAMER_COMPONENT(GSTREAMER_1_0_VIDEO gstreamer-video-1.0 gst/video/video.h gstvideo-1.0)
|
||||
|
||||
# ------------------------------------------------
|
||||
# 3. Process the COMPONENTS passed to FIND_PACKAGE
|
||||
# ------------------------------------------------
|
||||
set(_GSTREAMER_1_0_REQUIRED_VARS
|
||||
Glib_INCLUDE_DIRS
|
||||
Glib_LIBRARIES
|
||||
GSTREAMER_1_0_INCLUDE_DIRS
|
||||
GSTREAMER_1_0_LIBRARIES
|
||||
VERSION_OK
|
||||
GSTREAMER_1_0_BASE_INCLUDE_DIRS
|
||||
GSTREAMER_1_0_BASE_LIBRARIES)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GSTREAMER_1_0 DEFAULT_MSG GSTREAMER_1_0_LIBRARIES GSTREAMER_1_0_INCLUDE_DIRS)
|
||||
|
||||
list(APPEND GSTREAMER_1_0_INCLUDE_DIRS ${Glib_INCLUDE_DIRS})
|
||||
list(APPEND GSTREAMER_1_0_LIBRARIES ${Glib_LIBRARIES})
|
||||
list(APPEND GSTREAMER_1_0_INCLUDE_DIRS ${GSTREAMER_1_0_BASE_INCLUDE_DIRS})
|
||||
list(APPEND GSTREAMER_1_0_LIBRARIES ${GSTREAMER_1_0_BASE_LIBRARIES})
|
||||
list(APPEND GSTREAMER_1_0_INCLUDE_DIRS ${GSTREAMER_1_0_APP_INCLUDE_DIRS})
|
||||
list(APPEND GSTREAMER_1_0_LIBRARIES ${GSTREAMER_1_0_APP_LIBRARIES})
|
||||
list(APPEND GSTREAMER_1_0_INCLUDE_DIRS ${GSTREAMER_1_0_VIDEO_INCLUDE_DIRS})
|
||||
list(APPEND GSTREAMER_1_0_LIBRARIES ${GSTREAMER_1_0_VIDEO_LIBRARIES})
|
||||
|
||||
foreach (_component ${Gstreamer_FIND_COMPONENTS})
|
||||
set(_gst_component "GSTREAMER_1_0_${_component}")
|
||||
string(TOUPPER ${_gst_component} _UPPER_NAME)
|
||||
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(${_UPPER_NAME} DEFAULT_MSG ${_UPPER_NAME}_INCLUDE_DIRS ${_UPPER_NAME}_LIBRARIES)
|
||||
list(APPEND GSTREAMER_1_0_INCLUDE_DIRS ${${_UPPER_NAME}_INCLUDE_DIRS})
|
||||
list(APPEND GSTREAMER_1_0_LIBRARIES ${${_UPPER_NAME}_LIBRARIES})
|
||||
endforeach ()
|
||||
|
||||
MARK_AS_ADVANCED(GSTREAMER_1_0_INCLUDE_DIRS GSTREAMER_1_0_LIBRARIES GSTREAMER_1_0_BASE_LIBRARY GSTREAMER_1_0_APP_LIBRARY)
|
||||
|
43
cmake/FindGlib.cmake
Normal file
43
cmake/FindGlib.cmake
Normal file
@ -0,0 +1,43 @@
|
||||
# - Try to find Glib-2.0 (with gobject)
|
||||
# Once done, this will define
|
||||
#
|
||||
# Glib_FOUND - system has Glib
|
||||
# Glib_INCLUDE_DIRS - the Glib include directories
|
||||
# Glib_LIBRARIES - link these to use Glib
|
||||
#
|
||||
# GLIB_ROOT_DIR - Primary search directory
|
||||
include(LibFindMacros)
|
||||
|
||||
# Use pkg-config to get hints about paths
|
||||
libfind_pkg_check_modules(Glib_PKGCONF glib-2.0)
|
||||
|
||||
# Main include dir
|
||||
find_path(Glib_INCLUDE_DIR
|
||||
NAMES glib.h
|
||||
PATHS ${Glib_PKGCONF_INCLUDE_DIRS} ${GLIB_ROOT_DIR}
|
||||
PATH_SUFFIXES glib-2.0
|
||||
)
|
||||
|
||||
# Finally the library itself
|
||||
find_library(Glib_LIBRARY
|
||||
NAMES glib-2.0 gstreamer_android
|
||||
PATHS ${Glib_PKGCONF_LIBRARY_DIRS} ${GLIB_ROOT_DIR}
|
||||
)
|
||||
find_library(Gobject_LIBRARY
|
||||
NAMES gobject-2.0 gstreamer_android
|
||||
PATHS ${Glib_PKGCONF_LIBRARY_DIRS} ${GLIB_ROOT_DIR}
|
||||
)
|
||||
|
||||
# Glib-related libraries also use a separate config header, which is in lib dir
|
||||
find_path(GlibConfig_INCLUDE_DIR
|
||||
NAMES glibconfig.h
|
||||
PATHS ${Glib_PKGCONF_INCLUDE_DIRS} /usr ${GLIB_ROOT_DIR}
|
||||
PATH_SUFFIXES lib/glib-2.0/include glib-2.0/include
|
||||
)
|
||||
|
||||
# Set the include dir variables and the libraries and let libfind_process do the rest.
|
||||
# NOTE: Singular variables for this library, plural for libraries this this lib depends on.
|
||||
set(Glib_PROCESS_INCLUDES Glib_INCLUDE_DIR GlibConfig_INCLUDE_DIR)
|
||||
set(Glib_PROCESS_LIBS Glib_LIBRARY Gobject_LIBRARY)
|
||||
libfind_process(Glib)
|
||||
|
@ -1,12 +0,0 @@
|
||||
include(FindPkgConfig)
|
||||
|
||||
pkg_check_modules(PC_GSTREAMER_0_10 gstreamer-0.10)
|
||||
pkg_check_modules(PC_GSTREAMER_PLUGINS_BASE_0_10 gstreamer-plugins-base-0.10)
|
||||
|
||||
if(PC_GSTREAMER_0_10_FOUND AND PC_GSTREAMER_PLUGINS_BASE_0_10_FOUND)
|
||||
set(GSTREAMER_INCLUDE_DIRS ${PC_GSTREAMER_0_10_INCLUDE_DIRS} ${PC_GSTREAMER_PLUGINS_BASE_0_10_INCLUDE_DIRS})
|
||||
set(GSTREAMER_LIBRARIES ${PC_GSTREAMER_0_10_LIBRARIES} ${PC_GSTREAMER_PLUGINS_BASE_0_10_LIBRARIES})
|
||||
endif()
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
FIND_PACKAGE_HANDLE_STANDARD_ARGS(GSTREAMER DEFAULT_MSG GSTREAMER_LIBRARIES GSTREAMER_INCLUDE_DIRS)
|
116
cmake/LibFindMacros.cmake
Normal file
116
cmake/LibFindMacros.cmake
Normal file
@ -0,0 +1,116 @@
|
||||
# Works the same as find_package, but forwards the "REQUIRED" and "QUIET" arguments
|
||||
# used for the current package. For this to work, the first parameter must be the
|
||||
# prefix of the current package, then the prefix of the new package etc, which are
|
||||
# passed to find_package.
|
||||
macro(libfind_package PREFIX)
|
||||
set(LIBFIND_PACKAGE_ARGS $ {ARGN})
|
||||
if($ {PREFIX} _FIND_QUIETLY)
|
||||
set(LIBFIND_PACKAGE_ARGS $ {LIBFIND_PACKAGE_ARGS} QUIET)
|
||||
endif($ {PREFIX} _FIND_QUIETLY)
|
||||
if($ {PREFIX} _FIND_REQUIRED)
|
||||
set(LIBFIND_PACKAGE_ARGS $ {LIBFIND_PACKAGE_ARGS} REQUIRED)
|
||||
endif($ {PREFIX} _FIND_REQUIRED)
|
||||
find_package($ {LIBFIND_PACKAGE_ARGS})
|
||||
endmacro(libfind_package)
|
||||
|
||||
# CMake developers made the UsePkgConfig system deprecated in the same release (2.6)
|
||||
# where they added pkg_check_modules. Consequently I need to support both in my scripts
|
||||
# to avoid those deprecated warnings. Here's a helper that does just that.
|
||||
# Works identically to pkg_check_modules, except that no checks are needed prior to use.
|
||||
macro (libfind_pkg_check_modules PREFIX PKGNAME)
|
||||
if (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
|
||||
include(UsePkgConfig)
|
||||
pkgconfig(${PKGNAME} ${PREFIX}_INCLUDE_DIRS ${PREFIX}_LIBRARY_DIRS ${PREFIX}_LDFLAGS ${PREFIX}_CFLAGS)
|
||||
else (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
|
||||
find_package(PkgConfig)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(${PREFIX} ${PKGNAME})
|
||||
endif (PKG_CONFIG_FOUND)
|
||||
endif (${CMAKE_MAJOR_VERSION} EQUAL 2 AND ${CMAKE_MINOR_VERSION} EQUAL 4)
|
||||
endmacro (libfind_pkg_check_modules)
|
||||
|
||||
# Do the final processing once the paths have been detected.
|
||||
# If include dirs are needed, ${PREFIX}_PROCESS_INCLUDES should be set to contain
|
||||
# all the variables, each of which contain one include directory.
|
||||
# Ditto for ${PREFIX}_PROCESS_LIBS and library files.
|
||||
# Will set ${PREFIX}_FOUND, ${PREFIX}_INCLUDE_DIRS and ${PREFIX}_LIBRARIES.
|
||||
# Also handles errors in case library detection was required, etc.
|
||||
macro (libfind_process PREFIX)
|
||||
# Skip processing if already processed during this run
|
||||
if (NOT ${PREFIX}_FOUND)
|
||||
# Start with the assumption that the library was found
|
||||
set (${PREFIX}_FOUND TRUE)
|
||||
|
||||
# Process all includes and set _FOUND to false if any are missing
|
||||
foreach (i ${${PREFIX}_PROCESS_INCLUDES})
|
||||
if (${i})
|
||||
set (${PREFIX}_INCLUDE_DIRS ${${PREFIX}_INCLUDE_DIRS} ${${i}})
|
||||
mark_as_advanced(${i})
|
||||
else (${i})
|
||||
set (${PREFIX}_FOUND FALSE)
|
||||
endif (${i})
|
||||
endforeach (i)
|
||||
|
||||
# Process all libraries and set _FOUND to false if any are missing
|
||||
foreach (i ${${PREFIX}_PROCESS_LIBS})
|
||||
if (${i})
|
||||
set (${PREFIX}_LIBRARIES ${${PREFIX}_LIBRARIES} ${${i}})
|
||||
mark_as_advanced(${i})
|
||||
else (${i})
|
||||
set (${PREFIX}_FOUND FALSE)
|
||||
endif (${i})
|
||||
endforeach (i)
|
||||
|
||||
# Print message and/or exit on fatal error
|
||||
if (${PREFIX}_FOUND)
|
||||
if (NOT ${PREFIX}_FIND_QUIETLY)
|
||||
message (STATUS "Found ${PREFIX} ${${PREFIX}_VERSION}")
|
||||
endif (NOT ${PREFIX}_FIND_QUIETLY)
|
||||
else (${PREFIX}_FOUND)
|
||||
if (${PREFIX}_FIND_REQUIRED)
|
||||
foreach (i ${${PREFIX}_PROCESS_INCLUDES} ${${PREFIX}_PROCESS_LIBS})
|
||||
message("${i}=${${i}}")
|
||||
endforeach (i)
|
||||
message (FATAL_ERROR "Required library ${PREFIX} NOT FOUND.\nInstall the library (dev version) and try again. If the library is already installed, use ccmake to set the missing variables manually.")
|
||||
endif (${PREFIX}_FIND_REQUIRED)
|
||||
endif (${PREFIX}_FOUND)
|
||||
endif (NOT ${PREFIX}_FOUND)
|
||||
endmacro (libfind_process)
|
||||
|
||||
macro(libfind_library PREFIX basename)
|
||||
set(TMP "")
|
||||
if(MSVC80)
|
||||
set(TMP -vc80)
|
||||
endif(MSVC80)
|
||||
if(MSVC90)
|
||||
set(TMP -vc90)
|
||||
endif(MSVC90)
|
||||
set(${PREFIX}_LIBNAMES ${basename}${TMP})
|
||||
if(${ARGC} GREATER 2)
|
||||
set(${PREFIX}_LIBNAMES ${basename}${TMP}-${ARGV2})
|
||||
string(REGEX REPLACE "\\." "_" TMP ${${PREFIX}_LIBNAMES})
|
||||
set(${PREFIX}_LIBNAMES ${${PREFIX}_LIBNAMES} ${TMP})
|
||||
endif(${ARGC} GREATER 2)
|
||||
find_library(${PREFIX}_LIBRARY
|
||||
NAMES ${${PREFIX}_LIBNAMES}
|
||||
PATHS ${${PREFIX}_PKGCONF_LIBRARY_DIRS})
|
||||
endmacro(libfind_library)
|
||||
|
||||
SET(THREE_PART_VERSION_REGEX "[0-9]+\\.[0-9]+\\.[0-9]+")
|
||||
# Breaks up a string in the form n1.n2.n3 into three parts and stores
|
||||
# them in major, minor, and patch. version should be a value, not a
|
||||
# variable, while major, minor and patch should be variables.
|
||||
MACRO(THREE_PART_VERSION_TO_VARS version major minor patch)
|
||||
IF(${version} MATCHES ${THREE_PART_VERSION_REGEX})
|
||||
STRING(REPLACE "." " " version_list ${version})
|
||||
SEPARATE_ARGUMENTS(version_list)
|
||||
LIST(GET version_list 0 ${major})
|
||||
LIST(GET version_list 1 ${minor})
|
||||
LIST(GET version_list 2 ${patch})
|
||||
ELSE(${version} MATCHES ${THREE_PART_VERSION_REGEX})
|
||||
MESSAGE("MACRO(THREE_PART_VERSION_TO_VARS ${version} ${major} ${minor} ${patch}")
|
||||
MESSAGE(FATAL_ERROR "Problem parsing version string, I can't parse it properly.")
|
||||
ENDIF(${version} MATCHES ${THREE_PART_VERSION_REGEX})
|
||||
ENDMACRO(THREE_PART_VERSION_TO_VARS)
|
||||
|
||||
|
@ -39,6 +39,9 @@
|
||||
#cmakedefine WITH_WIN8
|
||||
#cmakedefine WITH_RDPSND_DSOUND
|
||||
|
||||
#cmakedefine WITH_FFMPEG
|
||||
#cmakedefine WITH_GSTREAMER_1_0
|
||||
#cmakedefine WITH_GSTREAMER_0_10
|
||||
#cmakedefine WITH_WINMM
|
||||
#cmakedefine WITH_MACAUDIO
|
||||
#cmakedefine WITH_ALSA
|
||||
@ -58,6 +61,7 @@
|
||||
#cmakedefine WITH_DEBUG_CHANNELS
|
||||
#cmakedefine WITH_DEBUG_CLIPRDR
|
||||
#cmakedefine WITH_DEBUG_DVC
|
||||
#cmakedefine WITH_DEBUG_TSMF
|
||||
#cmakedefine WITH_DEBUG_GDI
|
||||
#cmakedefine WITH_DEBUG_KBD
|
||||
#cmakedefine WITH_DEBUG_LICENSE
|
||||
|
63
include/freerdp/channels/tsmf.h
Normal file
63
include/freerdp/channels/tsmf.h
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Video Redirection Virtual Channel - Callback interface
|
||||
*
|
||||
* (C) Copyright 2014 Thincast Technologies GmbH
|
||||
* (C) Copyright 2014 Armin Novak <armin.novak@thincast.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 _TSMF_H_
|
||||
#define _TSMF_H_
|
||||
|
||||
#include <freerdp/types.h>
|
||||
|
||||
/* Callback function setup order:
|
||||
*
|
||||
* When the channel is loaded, it calls TSMF_REGISTER to register the
|
||||
* decoder handle with the client.
|
||||
* The client then stores the handle and calls TSMF_REGISTER_INSTANCE
|
||||
* to give the channel the current handle to the session necessary
|
||||
* to call other functions.
|
||||
* After this initial setup the other functions can be used.
|
||||
*/
|
||||
/* Functions called from client -> registered by channel */
|
||||
#define TSMF_GET_INSTANCE "tsmf_get_instance"
|
||||
typedef void (*tsmf_get_instance)(void *instance, void *decoder);
|
||||
|
||||
#define TSMF_ADD_WINDOW_HANDLE "tsmf_add_window_handle"
|
||||
typedef void (*tsmf_add_window_handle)(void *instance, void *decoder, void *window);
|
||||
|
||||
#define TSMF_DEL_WINDOW_HANDLE "tsmf_del_window_handle"
|
||||
typedef void (*tsmf_del_window_handle)(void *instance, void *decoder);
|
||||
|
||||
/* Functions called from channel -> registered by client */
|
||||
#define TSMF_REGISTER "tsmf_register"
|
||||
typedef void (*tsmf_register)(void *instance, void *decoder);
|
||||
|
||||
#define TSMF_DESTROY "tsmf_destroy"
|
||||
typedef void (*tsmf_destroy)(void *instance, void *decoder);
|
||||
|
||||
#define TSMF_PLAY "tsmf_play"
|
||||
typedef void (*tsmf_play)(void *instance, void *decoder);
|
||||
|
||||
#define TSMF_PAUSE "tsmf_pause"
|
||||
typedef void (*tsmf_pause)(void *instance, void *decoder);
|
||||
|
||||
#define TSMF_RESIZE_WINDOW "tsmf_resize_window"
|
||||
typedef void (*tsmf_resize_window)(void *instance, void *decoder, int x, int y, int width,
|
||||
int height, int nr_rect, RDP_RECT *visible);
|
||||
|
||||
#endif
|
||||
|
@ -35,6 +35,7 @@ FREERDP_API int freerdp_client_print_version(void);
|
||||
FREERDP_API int freerdp_client_print_command_line_help(int argc, char** argv);
|
||||
|
||||
FREERDP_API int freerdp_parse_username(char* username, char** user, char** domain);
|
||||
FREERDP_API int freerdp_parse_hostname(char* hostname, char** host, int* port);
|
||||
FREERDP_API int freerdp_set_connection_type(rdpSettings* settings, int type);
|
||||
|
||||
FREERDP_API int freerdp_client_add_device_channel(rdpSettings* settings, int count, char** params);
|
||||
|
@ -65,81 +65,79 @@ typedef struct _IWTSVirtualChannelCallback IWTSVirtualChannelCallback;
|
||||
struct _IWTSListener
|
||||
{
|
||||
/* Retrieves the listener-specific configuration. */
|
||||
int (*GetConfiguration) (IWTSListener* pListener,
|
||||
void** ppPropertyBag);
|
||||
int (*GetConfiguration)(IWTSListener *pListener,
|
||||
void **ppPropertyBag);
|
||||
|
||||
void* pInterface;
|
||||
void *pInterface;
|
||||
};
|
||||
|
||||
struct _IWTSVirtualChannel
|
||||
{
|
||||
/* Starts a write request on the channel. */
|
||||
int (*Write) (IWTSVirtualChannel* pChannel,
|
||||
UINT32 cbSize,
|
||||
BYTE* pBuffer,
|
||||
void* pReserved);
|
||||
int (*Write)(IWTSVirtualChannel *pChannel,
|
||||
UINT32 cbSize,
|
||||
BYTE *pBuffer,
|
||||
void *pReserved);
|
||||
/* Closes the channel. */
|
||||
int (*Close) (IWTSVirtualChannel* pChannel);
|
||||
int (*Close)(IWTSVirtualChannel *pChannel);
|
||||
};
|
||||
|
||||
struct _IWTSVirtualChannelManager
|
||||
{
|
||||
/* Returns an instance of a listener object that listens on a specific
|
||||
endpoint, or creates a static channel. */
|
||||
int (*CreateListener) (IWTSVirtualChannelManager* pChannelMgr,
|
||||
const char* pszChannelName,
|
||||
UINT32 ulFlags,
|
||||
IWTSListenerCallback* pListenerCallback,
|
||||
IWTSListener** ppListener);
|
||||
int (*CreateListener)(IWTSVirtualChannelManager *pChannelMgr,
|
||||
const char *pszChannelName,
|
||||
UINT32 ulFlags,
|
||||
IWTSListenerCallback *pListenerCallback,
|
||||
IWTSListener **ppListener);
|
||||
/* Push a virtual channel event.
|
||||
This is a FreeRDP extension to standard MS API. */
|
||||
int (*PushEvent) (IWTSVirtualChannelManager* pChannelMgr,
|
||||
wMessage* pEvent);
|
||||
int (*PushEvent)(IWTSVirtualChannelManager *pChannelMgr,
|
||||
wMessage *pEvent);
|
||||
/* Find the channel or ID to send data to a specific endpoint. */
|
||||
UINT32 (*GetChannelId) (IWTSVirtualChannel * channel);
|
||||
IWTSVirtualChannel* (*FindChannelById) (IWTSVirtualChannelManager* pChannelMgr,
|
||||
UINT32 ChannelId);
|
||||
UINT32(*GetChannelId)(IWTSVirtualChannel *channel);
|
||||
IWTSVirtualChannel *(*FindChannelById)(IWTSVirtualChannelManager *pChannelMgr,
|
||||
UINT32 ChannelId);
|
||||
};
|
||||
|
||||
struct _IWTSPlugin
|
||||
{
|
||||
/* Used for the first call that is made from the client to the plug-in. */
|
||||
int (*Initialize) (IWTSPlugin* pPlugin,
|
||||
IWTSVirtualChannelManager* pChannelMgr);
|
||||
int (*Initialize)(IWTSPlugin *pPlugin,
|
||||
IWTSVirtualChannelManager *pChannelMgr);
|
||||
/* Notifies the plug-in that the Remote Desktop Connection (RDC) client
|
||||
has successfully connected to the Remote Desktop Session Host (RD
|
||||
Session Host) server. */
|
||||
int (*Connected) (IWTSPlugin* pPlugin);
|
||||
int (*Connected)(IWTSPlugin *pPlugin);
|
||||
/* Notifies the plug-in that the Remote Desktop Connection (RDC) client
|
||||
has disconnected from the RD Session Host server. */
|
||||
int (*Disconnected) (IWTSPlugin* pPlugin,
|
||||
UINT32 dwDisconnectCode);
|
||||
int (*Disconnected)(IWTSPlugin *pPlugin,
|
||||
UINT32 dwDisconnectCode);
|
||||
/* Notifies the plug-in that the Remote Desktop Connection (RDC) client
|
||||
has terminated. */
|
||||
int (*Terminated) (IWTSPlugin* pPlugin);
|
||||
int (*Terminated)(IWTSPlugin *pPlugin);
|
||||
|
||||
/* Extended */
|
||||
|
||||
void* pInterface;
|
||||
void *pInterface;
|
||||
};
|
||||
|
||||
struct _IWTSListenerCallback
|
||||
{
|
||||
/* Accepts or denies a connection request for an incoming connection to
|
||||
the associated listener. */
|
||||
int (*OnNewChannelConnection) (IWTSListenerCallback* pListenerCallback,
|
||||
IWTSVirtualChannel* pChannel,
|
||||
BYTE* Data,
|
||||
int* pbAccept,
|
||||
IWTSVirtualChannelCallback** ppCallback);
|
||||
int (*OnNewChannelConnection)(IWTSListenerCallback *pListenerCallback,
|
||||
IWTSVirtualChannel *pChannel,
|
||||
BYTE *Data,
|
||||
int *pbAccept,
|
||||
IWTSVirtualChannelCallback **ppCallback);
|
||||
};
|
||||
|
||||
struct _IWTSVirtualChannelCallback
|
||||
{
|
||||
/* Notifies the user about data that is being received. */
|
||||
int (*OnDataReceived) (IWTSVirtualChannelCallback* pChannelCallback,
|
||||
UINT32 cbSize,
|
||||
BYTE* pBuffer);
|
||||
int (*OnDataReceived) (IWTSVirtualChannelCallback* pChannelCallback, wStream* data);
|
||||
/* Notifies the user that the channel has been opened. */
|
||||
int (*OnOpen) (IWTSVirtualChannelCallback* pChannelCallback);
|
||||
/* Notifies the user that the channel has been closed. */
|
||||
@ -150,13 +148,17 @@ struct _IWTSVirtualChannelCallback
|
||||
typedef struct _IDRDYNVC_ENTRY_POINTS IDRDYNVC_ENTRY_POINTS;
|
||||
struct _IDRDYNVC_ENTRY_POINTS
|
||||
{
|
||||
int (*RegisterPlugin) (IDRDYNVC_ENTRY_POINTS* pEntryPoints,
|
||||
const char* name, IWTSPlugin* pPlugin);
|
||||
IWTSPlugin* (*GetPlugin) (IDRDYNVC_ENTRY_POINTS* pEntryPoints,
|
||||
const char* name);
|
||||
ADDIN_ARGV* (*GetPluginData) (IDRDYNVC_ENTRY_POINTS* pEntryPoints);
|
||||
int (*RegisterPlugin)(IDRDYNVC_ENTRY_POINTS *pEntryPoints,
|
||||
const char *name, IWTSPlugin *pPlugin);
|
||||
IWTSPlugin *(*GetPlugin)(IDRDYNVC_ENTRY_POINTS *pEntryPoints,
|
||||
const char *name);
|
||||
ADDIN_ARGV *(*GetPluginData)(IDRDYNVC_ENTRY_POINTS *pEntryPoints);
|
||||
};
|
||||
|
||||
typedef int (*PDVC_PLUGIN_ENTRY) (IDRDYNVC_ENTRY_POINTS*);
|
||||
typedef int (*PDVC_PLUGIN_ENTRY)(IDRDYNVC_ENTRY_POINTS *);
|
||||
|
||||
void *get_callback_by_name(const char *name, void **context);
|
||||
void add_callback_by_name(const char *name, void *fkt, void *context);
|
||||
void remove_callback_by_name(const char *name, void *context);
|
||||
|
||||
#endif /* FREERDP_DVC_H */
|
||||
|
@ -85,11 +85,7 @@
|
||||
#define WITH_DEBUG_CREDSSP
|
||||
#endif
|
||||
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
#define NLA_PKG_NAME NTLMSP_NAME
|
||||
#else
|
||||
#define NLA_PKG_NAME NTLMSP_NAME
|
||||
#endif
|
||||
#define NLA_PKG_NAME NEGOSSP_NAME
|
||||
|
||||
#define TERMSRV_SPN_PREFIX "TERMSRV/"
|
||||
|
||||
@ -267,24 +263,7 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
if (credssp_ntlm_client_init(credssp) == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
{
|
||||
HMODULE hSSPI;
|
||||
INIT_SECURITY_INTERFACE InitSecurityInterface;
|
||||
PSecurityFunctionTable pSecurityInterface = NULL;
|
||||
|
||||
hSSPI = LoadLibrary(_T("secur32.dll"));
|
||||
|
||||
#ifdef UNICODE
|
||||
InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceW");
|
||||
#else
|
||||
InitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
|
||||
#endif
|
||||
credssp->table = (*InitSecurityInterface)();
|
||||
}
|
||||
#else
|
||||
credssp->table = InitSecurityInterface();
|
||||
#endif
|
||||
credssp->table = InitSecurityInterfaceEx(0);
|
||||
|
||||
status = credssp->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &pPackageInfo);
|
||||
|
||||
@ -337,17 +316,25 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
SECURITY_NATIVE_DREP, (have_input_buffer) ? &input_buffer_desc : NULL,
|
||||
0, &credssp->context, &output_buffer_desc, &pfContextAttr, &expiration);
|
||||
|
||||
if (have_input_buffer && (input_buffer.pvBuffer != NULL))
|
||||
if (have_input_buffer && (input_buffer.pvBuffer))
|
||||
{
|
||||
free(input_buffer.pvBuffer);
|
||||
input_buffer.pvBuffer = NULL;
|
||||
}
|
||||
|
||||
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED) || (status == SEC_E_OK))
|
||||
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
|
||||
{
|
||||
if (credssp->table->CompleteAuthToken != NULL)
|
||||
if (credssp->table->CompleteAuthToken)
|
||||
credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
status = SEC_E_OK;
|
||||
else if (status == SEC_I_COMPLETE_AND_CONTINUE)
|
||||
status = SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
if (status == SEC_E_OK)
|
||||
{
|
||||
have_pub_key_auth = TRUE;
|
||||
|
||||
if (credssp->table->QueryContextAttributes(&credssp->context, SECPKG_ATTR_SIZES, &credssp->ContextSizes) != SEC_E_OK)
|
||||
@ -357,11 +344,6 @@ int credssp_client_authenticate(rdpCredssp* credssp)
|
||||
}
|
||||
|
||||
credssp_encrypt_public_key_echo(credssp);
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
status = SEC_E_OK;
|
||||
else if (status == SEC_I_COMPLETE_AND_CONTINUE)
|
||||
status = SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
/* send authentication token to server */
|
||||
@ -469,11 +451,6 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
||||
if (credssp_ntlm_server_init(credssp) == 0)
|
||||
return 0;
|
||||
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
if (!credssp->SspiModule)
|
||||
credssp->SspiModule = _tcsdup(_T("secur32.dll"));
|
||||
#endif
|
||||
|
||||
if (credssp->SspiModule)
|
||||
{
|
||||
HMODULE hSSPI;
|
||||
@ -493,14 +470,12 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
||||
pInitSecurityInterface = (INIT_SECURITY_INTERFACE) GetProcAddress(hSSPI, "InitSecurityInterfaceA");
|
||||
#endif
|
||||
|
||||
credssp->table = (*pInitSecurityInterface)();
|
||||
credssp->table = pInitSecurityInterface();
|
||||
}
|
||||
#ifndef WITH_NATIVE_SSPI
|
||||
else
|
||||
{
|
||||
credssp->table = InitSecurityInterface();
|
||||
credssp->table = InitSecurityInterfaceEx(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
status = credssp->table->QuerySecurityPackageInfo(NLA_PKG_NAME, &pPackageInfo);
|
||||
|
||||
@ -597,7 +572,7 @@ int credssp_server_authenticate(rdpCredssp* credssp)
|
||||
|
||||
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
|
||||
{
|
||||
if (credssp->table->CompleteAuthToken != NULL)
|
||||
if (credssp->table->CompleteAuthToken)
|
||||
credssp->table->CompleteAuthToken(&credssp->context, &output_buffer_desc);
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
@ -1385,7 +1360,7 @@ rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings*
|
||||
{
|
||||
rdpCredssp* credssp;
|
||||
|
||||
credssp = (rdpCredssp*) malloc(sizeof(rdpCredssp));
|
||||
credssp = (rdpCredssp*) calloc(1, sizeof(rdpCredssp));
|
||||
|
||||
if (credssp)
|
||||
{
|
||||
@ -1394,8 +1369,6 @@ rdpCredssp* credssp_new(freerdp* instance, rdpTransport* transport, rdpSettings*
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
|
||||
ZeroMemory(credssp, sizeof(rdpCredssp));
|
||||
|
||||
credssp->instance = instance;
|
||||
credssp->settings = settings;
|
||||
credssp->server = settings->ServerMode;
|
||||
|
23
scripts/format_code.sh
Executable file
23
scripts/format_code.sh
Executable file
@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
|
||||
ASTYLE=`which astyle`
|
||||
|
||||
if [ ! -x $ASTYLE ];
|
||||
then
|
||||
echo "No astyle found in path, please install."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ $# -le 0 ]; then
|
||||
echo "Usage:"
|
||||
echo "\t$0 <file1> [<file2> ...]"
|
||||
# echo "\t$0 -r <directory>"
|
||||
exit 2
|
||||
fi
|
||||
|
||||
$ASTYLE --lineend=linux --mode=c --indent=force-tab=4 --brackets=linux --pad-header \
|
||||
--indent-switches --indent-cases --indent-preprocessor \
|
||||
--indent-col1-comments --delete-empty-lines --break-closing-brackets \
|
||||
--align-pointer=name --indent-labels --brackets=break \
|
||||
--unpad-paren --break-blocks $@
|
||||
exit $?
|
@ -541,6 +541,10 @@ static void* xf_peer_main_loop(void* arg)
|
||||
settings->RemoteFxCodec = TRUE;
|
||||
settings->ColorDepth = 32;
|
||||
|
||||
settings->NlaSecurity = FALSE;
|
||||
settings->TlsSecurity = TRUE;
|
||||
settings->RdpSecurity = FALSE;
|
||||
|
||||
client->Capabilities = xf_peer_capabilities;
|
||||
client->PostConnect = xf_peer_post_connect;
|
||||
client->Activate = xf_peer_activate;
|
||||
|
@ -67,9 +67,6 @@ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DWINPR_EXPORTS")
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include)
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR}/include)
|
||||
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/include/winpr/config.h.in
|
||||
${CMAKE_CURRENT_BINARY_DIR}/include/winpr/config.h)
|
||||
|
||||
add_subdirectory(include)
|
||||
|
||||
add_subdirectory(libwinpr)
|
||||
|
@ -29,7 +29,22 @@
|
||||
|
||||
#include <wincrypt.h>
|
||||
|
||||
#else
|
||||
#endif
|
||||
|
||||
#ifndef ALG_TYPE_RESERVED7
|
||||
#define ALG_TYPE_RESERVED7 (7 << 9)
|
||||
#endif
|
||||
|
||||
#if (NTDDI_VERSION <= 0x05010200)
|
||||
#define ALG_SID_SHA_256 12
|
||||
#define ALG_SID_SHA_384 13
|
||||
#define ALG_SID_SHA_512 14
|
||||
#define CALG_SHA_256 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_256)
|
||||
#define CALG_SHA_384 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_384)
|
||||
#define CALG_SHA_512 (ALG_CLASS_HASH | ALG_TYPE_ANY | ALG_SID_SHA_512)
|
||||
#endif
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
/* ncrypt.h */
|
||||
|
||||
@ -60,7 +75,6 @@ typedef ULONG_PTR NCRYPT_SECRET_HANDLE;
|
||||
#define ALG_TYPE_STREAM (4 << 9)
|
||||
#define ALG_TYPE_DH (5 << 9)
|
||||
#define ALG_TYPE_SECURECHANNEL (6 << 9)
|
||||
#define ALG_TYPE_RESERVED7 (7 << 9)
|
||||
|
||||
#define ALG_SID_ANY (0)
|
||||
|
||||
@ -74,8 +88,6 @@ typedef ULONG_PTR NCRYPT_SECRET_HANDLE;
|
||||
#define ALG_SID_DSS_PKCS 1
|
||||
#define ALG_SID_DSS_DMS 2
|
||||
|
||||
#define ALG_SID_ECDSA 3
|
||||
|
||||
#define ALG_SID_DES 1
|
||||
#define ALG_SID_3DES 3
|
||||
#define ALG_SID_DESX 4
|
||||
@ -192,7 +204,6 @@ typedef ULONG_PTR NCRYPT_SECRET_HANDLE;
|
||||
|
||||
#define CALG_ECDH (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_DH | ALG_SID_ECDH)
|
||||
#define CALG_ECMQV (ALG_CLASS_KEY_EXCHANGE | ALG_TYPE_ANY | ALG_SID_ECMQV)
|
||||
#define CALG_ECDSA (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_ECDSA)
|
||||
|
||||
typedef struct _CRYPTOAPI_BLOB
|
||||
{
|
||||
@ -594,5 +605,10 @@ BOOL CryptBinaryToStringA(CONST BYTE* pbBinary, DWORD cbBinary, DWORD dwFlags, L
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef ALG_SID_ECSDA
|
||||
#define ALG_SID_ECDSA 3
|
||||
#define CALG_ECDSA (ALG_CLASS_SIGNATURE | ALG_TYPE_DSS | ALG_SID_ECDSA)
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_CRYPTO_H */
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Security Support Provider Interface (SSPI)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -20,37 +20,23 @@
|
||||
#ifndef WINPR_SSPI_H
|
||||
#define WINPR_SSPI_H
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <wchar.h>
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/windows.h>
|
||||
#include <winpr/security.h>
|
||||
|
||||
#define _NO_KSECDD_IMPORT_ 1
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <tchar.h>
|
||||
#include <winerror.h>
|
||||
|
||||
#ifdef WITH_NATIVE_SSPI
|
||||
#define SECURITY_WIN32
|
||||
#include <sspi.h>
|
||||
#include <security.h>
|
||||
#else
|
||||
#define WINPR_SSPI
|
||||
#define SEC_ENTRY __stdcall
|
||||
#endif
|
||||
|
||||
#else
|
||||
|
||||
#define WINPR_SSPI
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WINPR_SSPI
|
||||
#ifndef _WIN32
|
||||
|
||||
#ifndef SEC_ENTRY
|
||||
#define SEC_ENTRY
|
||||
@ -266,7 +252,7 @@ typedef SecPkgInfoW* PSecPkgInfoW;
|
||||
#define SECPKG_ATTR_NEGO_STATUS 32
|
||||
#define SECPKG_ATTR_CONTEXT_DELETED 33
|
||||
|
||||
#ifdef WINPR_SSPI
|
||||
#ifndef _WIN32
|
||||
|
||||
struct _SecPkgContext_AccessToken
|
||||
{
|
||||
@ -593,7 +579,7 @@ typedef SecPkgCredentials_NamesW* PSecPkgCredentials_NamesW;
|
||||
#define SEC_WINNT_AUTH_IDENTITY_ANSI 0x1
|
||||
#define SEC_WINNT_AUTH_IDENTITY_UNICODE 0x2
|
||||
|
||||
#ifdef WINPR_SSPI
|
||||
#ifndef _WIN32
|
||||
|
||||
typedef struct _SEC_WINNT_AUTH_IDENTITY_W
|
||||
{
|
||||
@ -679,7 +665,7 @@ typedef CtxtHandle* PCtxtHandle;
|
||||
#define SECBUFFER_READONLY_WITH_CHECKSUM 0x10000000
|
||||
#define SECBUFFER_RESERVED 0x60000000
|
||||
|
||||
#ifdef WINPR_SSPI
|
||||
#ifndef _WIN32
|
||||
|
||||
struct _SecBuffer
|
||||
{
|
||||
@ -1000,8 +986,7 @@ WINPR_API SECURITY_STATUS SEC_ENTRY VerifySignature(PCtxtHandle phContext, PSecB
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // WINPR_SSPI
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
@ -1009,14 +994,56 @@ extern "C" {
|
||||
|
||||
/* Custom API */
|
||||
|
||||
#define SECPKG_ATTR_AUTH_IDENTITY 1001
|
||||
#define SECPKG_ATTR_AUTH_PASSWORD 1002
|
||||
#define SECPKG_ATTR_AUTH_NTLM_HASH 1003
|
||||
|
||||
struct _SecPkgContext_AuthIdentity
|
||||
{
|
||||
char User[256 + 1];
|
||||
char Domain[256 + 1];
|
||||
};
|
||||
typedef struct _SecPkgContext_AuthIdentity SecPkgContext_AuthIdentity;
|
||||
|
||||
struct _SecPkgContext_AuthPassword
|
||||
{
|
||||
char Password[256 + 1];
|
||||
};
|
||||
typedef struct _SecPkgContext_AuthPassword SecPkgContext_AuthPassword;
|
||||
|
||||
struct _SecPkgContext_AuthNtlmHash
|
||||
{
|
||||
BYTE NtlmHash[16];
|
||||
};
|
||||
typedef struct _SecPkgContext_AuthNtlmHash SecPkgContext_AuthNtlmHash;
|
||||
|
||||
#define SSPI_INTERFACE_WINPR 0x00000001
|
||||
#define SSPI_INTERFACE_NATIVE 0x00000002
|
||||
|
||||
typedef PSecurityFunctionTableA (SEC_ENTRY * INIT_SECURITY_INTERFACE_EX_A)(DWORD flags);
|
||||
typedef PSecurityFunctionTableW (SEC_ENTRY * INIT_SECURITY_INTERFACE_EX_W)(DWORD flags);
|
||||
|
||||
WINPR_API void sspi_GlobalInit(void);
|
||||
WINPR_API void sspi_GlobalFinish(void);
|
||||
|
||||
WINPR_API void sspi_SecBufferAlloc(PSecBuffer SecBuffer, ULONG size);
|
||||
WINPR_API void* sspi_SecBufferAlloc(PSecBuffer SecBuffer, ULONG size);
|
||||
WINPR_API void sspi_SecBufferFree(PSecBuffer SecBuffer);
|
||||
|
||||
WINPR_API void sspi_SetAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, char* user, char* domain, char* password);
|
||||
WINPR_API void sspi_CopyAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, SEC_WINNT_AUTH_IDENTITY* srcIdentity);
|
||||
WINPR_API int sspi_SetAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, const char* user, const char* domain, const char* password);
|
||||
WINPR_API int sspi_CopyAuthIdentity(SEC_WINNT_AUTH_IDENTITY* identity, SEC_WINNT_AUTH_IDENTITY* srcIdentity);
|
||||
|
||||
WINPR_API const char* GetSecurityStatusString(SECURITY_STATUS status);
|
||||
|
||||
WINPR_API SecurityFunctionTableW* SEC_ENTRY InitSecurityInterfaceExW(DWORD flags);
|
||||
WINPR_API SecurityFunctionTableA* SEC_ENTRY InitSecurityInterfaceExA(DWORD flags);
|
||||
|
||||
#ifdef UNICODE
|
||||
#define InitSecurityInterfaceEx InitSecurityInterfaceExW
|
||||
#define INIT_SECURITY_INTERFACE_EX INIT_SECURITY_INTERFACE_EX_W
|
||||
#else
|
||||
#define InitSecurityInterfaceEx InitSecurityInterfaceExA
|
||||
#define INIT_SECURITY_INTERFACE_EX INIT_SECURITY_INTERFACE_EX_A
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -62,7 +62,11 @@ WINPR_API BOOL TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZon
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0600)) /* Windows Vista */
|
||||
/*
|
||||
* GetDynamicTimeZoneInformation is provided by the SDK if _WIN32_WINNT >= 0x0600 in SDKs above 7.1A
|
||||
* and incorrectly if _WIN32_WINNT >= 0x0501 in older SDKs
|
||||
*/
|
||||
#if !defined(_WIN32) || (defined(_WIN32) && (defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0600 || !defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0501)) /* Windows Vista */
|
||||
|
||||
WINPR_API DWORD GetDynamicTimeZoneInformation(PDYNAMIC_TIME_ZONE_INFORMATION pTimeZoneInformation);
|
||||
WINPR_API BOOL SetDynamicTimeZoneInformation(const DYNAMIC_TIME_ZONE_INFORMATION* lpTimeZoneInformation);
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include <wctype.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/error.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
#ifndef _WIN32
|
||||
@ -303,7 +304,15 @@ int ConvertToUnicode(UINT CodePage, DWORD dwFlags, LPCSTR lpMultiByteStr,
|
||||
allocate = TRUE;
|
||||
|
||||
if (allocate)
|
||||
*lpWideCharStr = (LPWSTR) malloc(cchWideChar * sizeof(WCHAR));
|
||||
{
|
||||
*lpWideCharStr = (LPWSTR) calloc(cchWideChar, sizeof(WCHAR));
|
||||
|
||||
if (!(*lpWideCharStr))
|
||||
{
|
||||
//SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
status = MultiByteToWideChar(CodePage, dwFlags, lpMultiByteStr, cbMultiByte, *lpWideCharStr, cchWideChar);
|
||||
|
||||
@ -342,15 +351,22 @@ int ConvertFromUnicode(UINT CodePage, DWORD dwFlags, LPCWSTR lpWideCharStr, int
|
||||
|
||||
if (allocate)
|
||||
{
|
||||
*lpMultiByteStr = (LPSTR) malloc(cbMultiByte + 1);
|
||||
ZeroMemory(*lpMultiByteStr, cbMultiByte + 1);
|
||||
*lpMultiByteStr = (LPSTR) calloc(1, cbMultiByte + 1);
|
||||
|
||||
if (!(*lpMultiByteStr))
|
||||
{
|
||||
//SetLastError(ERROR_INSUFFICIENT_BUFFER);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
status = WideCharToMultiByte(CodePage, dwFlags, lpWideCharStr, cchWideChar,
|
||||
*lpMultiByteStr, cbMultiByte, lpDefaultChar, lpUsedDefaultChar);
|
||||
|
||||
if (status != cbMultiByte)
|
||||
if ((status != cbMultiByte) && allocate)
|
||||
{
|
||||
status = 0;
|
||||
}
|
||||
|
||||
if ((status <= 0) && allocate)
|
||||
{
|
||||
|
@ -193,7 +193,6 @@ static void* named_pipe_single_thread(void* arg)
|
||||
{
|
||||
HANDLE servers[TESTNUMPIPESST];
|
||||
HANDLE clients[TESTNUMPIPESST];
|
||||
WINPR_NAMED_PIPE* p;
|
||||
char sndbuf[PIPE_BUFFER_SIZE];
|
||||
char rcvbuf[PIPE_BUFFER_SIZE];
|
||||
DWORD dwRead;
|
||||
@ -201,6 +200,9 @@ static void* named_pipe_single_thread(void* arg)
|
||||
int i;
|
||||
int numPipes;
|
||||
BOOL bSuccess = FALSE;
|
||||
#ifndef _WIN32
|
||||
WINPR_NAMED_PIPE* p;
|
||||
#endif
|
||||
|
||||
numPipes = TESTNUMPIPESST;
|
||||
|
||||
@ -220,6 +222,7 @@ static void* named_pipe_single_thread(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
for (i = 0; i < numPipes; i++)
|
||||
{
|
||||
p = (WINPR_NAMED_PIPE*)servers[i];
|
||||
@ -252,6 +255,7 @@ static void* named_pipe_single_thread(void* arg)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 0; i < numPipes; i++)
|
||||
{
|
||||
@ -269,9 +273,11 @@ static void* named_pipe_single_thread(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef _WIN32
|
||||
for (i = 0; i < numPipes; i++)
|
||||
{
|
||||
p = servers[i];
|
||||
|
||||
if (p->clientfd < 1)
|
||||
{
|
||||
printf("%s: Unexpected client fd value for pipe #%d (%d is not > 0)\n",
|
||||
@ -279,7 +285,7 @@ static void* named_pipe_single_thread(void* arg)
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (p->ServerMode == TRUE)
|
||||
if (p->ServerMode)
|
||||
{
|
||||
printf("%s: Unexpected ServerMode value for pipe #%d (1 instead of 0)\n",
|
||||
__FUNCTION__, i);
|
||||
@ -291,11 +297,12 @@ static void* named_pipe_single_thread(void* arg)
|
||||
{
|
||||
/* Test writing from clients to servers */
|
||||
|
||||
memset(sndbuf, 0, sizeof(sndbuf));
|
||||
memset(rcvbuf, 0, sizeof(rcvbuf));
|
||||
snprintf(sndbuf, sizeof(sndbuf), "CLIENT->SERVER ON PIPE #%05d", i);
|
||||
ZeroMemory(sndbuf, sizeof(sndbuf));
|
||||
ZeroMemory(rcvbuf, sizeof(rcvbuf));
|
||||
sprintf_s(sndbuf, sizeof(sndbuf), "CLIENT->SERVER ON PIPE #%05d", i);
|
||||
|
||||
p = servers[i];
|
||||
|
||||
if (!WriteFile(clients[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL) ||
|
||||
dwWritten != sizeof(sndbuf))
|
||||
{
|
||||
@ -319,9 +326,9 @@ static void* named_pipe_single_thread(void* arg)
|
||||
|
||||
/* Test writing from servers to clients */
|
||||
|
||||
memset(sndbuf, 0, sizeof(sndbuf));
|
||||
memset(rcvbuf, 0, sizeof(rcvbuf));
|
||||
snprintf(sndbuf, sizeof(sndbuf), "SERVER->CLIENT ON PIPE #%05d", i);
|
||||
ZeroMemory(sndbuf, sizeof(sndbuf));
|
||||
ZeroMemory(rcvbuf, sizeof(rcvbuf));
|
||||
sprintf_s(sndbuf, sizeof(sndbuf), "SERVER->CLIENT ON PIPE #%05d", i);
|
||||
|
||||
p = servers[i];
|
||||
if (!WriteFile(servers[i], sndbuf, sizeof(sndbuf), &dwWritten, NULL) ||
|
||||
@ -345,6 +352,7 @@ static void* named_pipe_single_thread(void* arg)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* After DisconnectNamedPipe on server end
|
||||
|
@ -43,20 +43,21 @@ set(${MODULE_PREFIX}_CREDSSP_SRCS
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_CREDSSP_SRCS}
|
||||
sspi_winpr.c
|
||||
sspi_winpr.h
|
||||
sspi_export.c
|
||||
sspi.c
|
||||
sspi.h)
|
||||
|
||||
if(NOT WITH_NATIVE_SSPI)
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_NTLM_SRCS}
|
||||
${${MODULE_PREFIX}_KERBEROS_SRCS}
|
||||
${${MODULE_PREFIX}_NEGOTIATE_SRCS}
|
||||
${${MODULE_PREFIX}_SCHANNEL_SRCS}
|
||||
${${MODULE_PREFIX}_SRCS})
|
||||
endif()
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_NTLM_SRCS}
|
||||
${${MODULE_PREFIX}_KERBEROS_SRCS}
|
||||
${${MODULE_PREFIX}_NEGOTIATE_SRCS}
|
||||
${${MODULE_PREFIX}_SCHANNEL_SRCS}
|
||||
${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
if(MSVC AND (NOT MONOLITHIC_BUILD))
|
||||
set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def)
|
||||
#set(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_SRCS} module.def)
|
||||
endif()
|
||||
|
||||
add_complex_library(MODULE ${MODULE_NAME} TYPE "OBJECT"
|
||||
@ -80,7 +81,7 @@ endif()
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
|
||||
MODULE winpr
|
||||
MODULES winpr-crt winpr-sysinfo winpr-registry winpr-crypto winpr-utils)
|
||||
MODULES winpr-crt winpr-sysinfo winpr-registry winpr-crypto winpr-library winpr-utils)
|
||||
|
||||
if(MONOLITHIC_BUILD)
|
||||
set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Credential Security Support Provider (CredSSP)
|
||||
*
|
||||
* Copyright 2010-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2010-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -35,7 +35,7 @@ SECURITY_STATUS SEC_ENTRY credssp_InitializeSecurityContextW(PCredHandle phCrede
|
||||
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_InitializeSecurityContextA(PCredHandle phCredential, PCtxtHandle phContext,
|
||||
@ -44,22 +44,24 @@ SECURITY_STATUS SEC_ENTRY credssp_InitializeSecurityContextA(PCredHandle phCrede
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
CREDSSP_CONTEXT* context;
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
context = sspi_SecureHandleGetLowerPointer(phContext);
|
||||
context = (CREDSSP_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = credssp_ContextNew();
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
if (!context)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) CREDSSP_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
|
||||
}
|
||||
|
||||
CREDSSP_CONTEXT* credssp_ContextNew()
|
||||
@ -68,10 +70,8 @@ CREDSSP_CONTEXT* credssp_ContextNew()
|
||||
|
||||
context = (CREDSSP_CONTEXT*) calloc(1, sizeof(CREDSSP_CONTEXT));
|
||||
|
||||
if (context != NULL)
|
||||
{
|
||||
|
||||
}
|
||||
if (!context)
|
||||
return NULL;
|
||||
|
||||
return context;
|
||||
}
|
||||
@ -99,19 +99,23 @@ SECURITY_STATUS SEC_ENTRY credssp_AcquireCredentialsHandleW(SEC_WCHAR* pszPrinci
|
||||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
|
||||
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal, SEC_CHAR* pszPackage,
|
||||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
|
||||
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SEC_WINNT_AUTH_IDENTITY* identity;
|
||||
|
||||
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
@ -122,21 +126,21 @@ SECURITY_STATUS SEC_ENTRY credssp_AcquireCredentialsHandleA(SEC_CHAR* pszPrincip
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesW(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesA(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
@ -146,12 +150,12 @@ SECURITY_STATUS SEC_ENTRY credssp_QueryCredentialsAttributesA(PCredHandle phCred
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_FreeCredentialsHandle(PCredHandle phCredential)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
if (!phCredential)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
@ -163,22 +167,22 @@ SECURITY_STATUS SEC_ENTRY credssp_FreeCredentialsHandle(PCredHandle phCredential
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_MakeSignature(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY credssp_VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
const SecurityFunctionTableA CREDSSP_SecurityFunctionTableA =
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -41,145 +41,195 @@
|
||||
|
||||
char* NTLM_PACKAGE_NAME = "NTLM";
|
||||
|
||||
void ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
|
||||
int ntlm_SetContextWorkstation(NTLM_CONTEXT* context, char* Workstation)
|
||||
{
|
||||
char *ws = Workstation;
|
||||
int status;
|
||||
DWORD nSize = 0;
|
||||
char* ws = Workstation;
|
||||
|
||||
if (!Workstation)
|
||||
{
|
||||
GetComputerNameExA(ComputerNameNetBIOS, NULL, &nSize);
|
||||
ws = malloc(nSize);
|
||||
GetComputerNameExA(ComputerNameNetBIOS, ws, &nSize);
|
||||
|
||||
ws = (char*) malloc(nSize);
|
||||
|
||||
if (!ws)
|
||||
return -1;
|
||||
|
||||
if (!GetComputerNameExA(ComputerNameNetBIOS, ws, &nSize))
|
||||
return 0;
|
||||
}
|
||||
|
||||
context->Workstation.Length = ConvertToUnicode(CP_UTF8, 0,
|
||||
ws, -1, &context->Workstation.Buffer, 0) - 1;
|
||||
context->Workstation.Buffer = NULL;
|
||||
status = ConvertToUnicode(CP_UTF8, 0, ws, -1, &context->Workstation.Buffer, 0);
|
||||
free(ws);
|
||||
|
||||
if (status <= 0)
|
||||
return -1;
|
||||
|
||||
context->Workstation.Length = (USHORT) (status - 1);
|
||||
context->Workstation.Length *= 2;
|
||||
|
||||
if (!Workstation)
|
||||
free(Workstation);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
|
||||
int ntlm_SetContextServicePrincipalNameW(NTLM_CONTEXT* context, LPWSTR ServicePrincipalName)
|
||||
{
|
||||
context->ServicePrincipalName.Length = _wcslen(ServicePrincipalName) * 2;
|
||||
if (!ServicePrincipalName)
|
||||
{
|
||||
context->ServicePrincipalName.Buffer = NULL;
|
||||
return;
|
||||
context->ServicePrincipalName.Length = 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
context->ServicePrincipalName.Length = _wcslen(ServicePrincipalName) * 2;
|
||||
context->ServicePrincipalName.Buffer = (PWSTR) malloc(context->ServicePrincipalName.Length + 2);
|
||||
|
||||
if (!context->ServicePrincipalName.Buffer)
|
||||
return -1;
|
||||
|
||||
CopyMemory(context->ServicePrincipalName.Buffer, ServicePrincipalName, context->ServicePrincipalName.Length + 2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_SetContextServicePrincipalNameA(NTLM_CONTEXT* context, char* ServicePrincipalName)
|
||||
int ntlm_SetContextServicePrincipalNameA(NTLM_CONTEXT* context, char* ServicePrincipalName)
|
||||
{
|
||||
context->ServicePrincipalName.Length = ConvertToUnicode(CP_UTF8, 0,
|
||||
ServicePrincipalName, -1, &context->ServicePrincipalName.Buffer, 0) - 1;
|
||||
context->ServicePrincipalName.Length *= 2;
|
||||
int status;
|
||||
|
||||
context->ServicePrincipalName.Buffer = NULL;
|
||||
|
||||
status = ConvertToUnicode(CP_UTF8, 0, ServicePrincipalName, -1, &context->ServicePrincipalName.Buffer, 0);
|
||||
|
||||
if (status <= 0)
|
||||
return -1;
|
||||
|
||||
context->ServicePrincipalName.Length = (USHORT) ((status - 1) * 2);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
|
||||
int ntlm_SetContextTargetName(NTLM_CONTEXT* context, char* TargetName)
|
||||
{
|
||||
char *name = TargetName;
|
||||
int status;
|
||||
DWORD nSize = 0;
|
||||
char* name = TargetName;
|
||||
|
||||
if (!TargetName)
|
||||
{
|
||||
GetComputerNameExA(ComputerNameDnsHostname, NULL, &nSize);
|
||||
name = malloc(nSize);
|
||||
GetComputerNameExA(ComputerNameDnsHostname, name, &nSize);
|
||||
if (!GetComputerNameExA(ComputerNameDnsHostname, NULL, &nSize))
|
||||
return -1;
|
||||
|
||||
name = (char*) malloc(nSize);
|
||||
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
if (!GetComputerNameExA(ComputerNameDnsHostname, name, &nSize))
|
||||
return -1;
|
||||
|
||||
CharUpperA(TargetName);
|
||||
}
|
||||
|
||||
context->TargetName.cbBuffer = ConvertToUnicode(CP_UTF8, 0,
|
||||
name, -1, (LPWSTR*) &context->TargetName.pvBuffer, 0) - 1;
|
||||
context->TargetName.cbBuffer *= 2;
|
||||
context->TargetName.pvBuffer = NULL;
|
||||
status = ConvertToUnicode(CP_UTF8, 0, name, -1, (LPWSTR*) &context->TargetName.pvBuffer, 0);
|
||||
|
||||
if (status <= 0)
|
||||
return -1;
|
||||
|
||||
context->TargetName.cbBuffer = (USHORT) ((status - 1) * 2);
|
||||
|
||||
if (!TargetName)
|
||||
free(name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
NTLM_CONTEXT* ntlm_ContextNew()
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG status;
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
DWORD dwValue;
|
||||
NTLM_CONTEXT* context;
|
||||
|
||||
context = (NTLM_CONTEXT*) malloc(sizeof(NTLM_CONTEXT));
|
||||
ZeroMemory(context, sizeof(NTLM_CONTEXT));
|
||||
context = (NTLM_CONTEXT*) calloc(1, sizeof(NTLM_CONTEXT));
|
||||
|
||||
if (context != NULL)
|
||||
if (!context)
|
||||
return NULL;
|
||||
|
||||
context->NTLMv2 = TRUE;
|
||||
context->UseMIC = FALSE;
|
||||
context->SendVersionInfo = TRUE;
|
||||
context->SendSingleHostData = FALSE;
|
||||
context->SendWorkstationName = TRUE;
|
||||
|
||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\WinPR\\NTLM"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG status;
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
DWORD dwValue;
|
||||
if (RegQueryValueEx(hKey, _T("NTLMv2"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->NTLMv2 = dwValue ? 1 : 0;
|
||||
|
||||
context->NTLMv2 = TRUE;
|
||||
context->UseMIC = FALSE;
|
||||
context->SendVersionInfo = TRUE;
|
||||
context->SendSingleHostData = FALSE;
|
||||
context->SendWorkstationName = TRUE;
|
||||
if (RegQueryValueEx(hKey, _T("UseMIC"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->UseMIC = dwValue ? 1 : 0;
|
||||
|
||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\WinPR\\NTLM"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
if (RegQueryValueEx(hKey, _T("SendVersionInfo"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SendVersionInfo = dwValue ? 1 : 0;
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
if (RegQueryValueEx(hKey, _T("SendSingleHostData"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SendSingleHostData = dwValue ? 1 : 0;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("SendWorkstationName"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SendWorkstationName = dwValue ? 1 : 0;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("WorkstationName"), NULL, &dwType, NULL, &dwSize) == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("NTLMv2"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->NTLMv2 = dwValue ? 1 : 0;
|
||||
char* workstation = (char*) malloc(dwSize + 1);
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("UseMIC"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->UseMIC = dwValue ? 1 : 0;
|
||||
if (!workstation)
|
||||
return NULL;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("SendVersionInfo"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SendVersionInfo = dwValue ? 1 : 0;
|
||||
status = RegQueryValueExA(hKey, "WorkstationName", NULL, &dwType, (BYTE*) workstation, &dwSize);
|
||||
workstation[dwSize] = '\0';
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("SendSingleHostData"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SendSingleHostData = dwValue ? 1 : 0;
|
||||
if (ntlm_SetContextWorkstation(context, workstation) < 0)
|
||||
return NULL;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("SendWorkstationName"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SendWorkstationName = dwValue ? 1 : 0;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("WorkstationName"), NULL, &dwType, NULL, &dwSize) == ERROR_SUCCESS)
|
||||
{
|
||||
char* workstation = (char*) malloc(dwSize + 1);
|
||||
|
||||
status = RegQueryValueExA(hKey, "WorkstationName", NULL, &dwType, (BYTE*) workstation, &dwSize);
|
||||
workstation[dwSize] = '\0';
|
||||
|
||||
ntlm_SetContextWorkstation(context, workstation);
|
||||
free(workstation);
|
||||
}
|
||||
|
||||
RegCloseKey(hKey);
|
||||
free(workstation);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended Protection is enabled by default in Windows 7,
|
||||
* but enabling it in WinPR breaks TS Gateway at this point
|
||||
*/
|
||||
context->SuppressExtendedProtection = FALSE;
|
||||
|
||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Control\\LSA"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("SuppressExtendedProtection"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SuppressExtendedProtection = dwValue ? 1 : 0;
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
context->NegotiateFlags = 0;
|
||||
context->LmCompatibilityLevel = 3;
|
||||
context->state = NTLM_STATE_INITIAL;
|
||||
memset(context->MachineID, 0xAA, sizeof(context->MachineID));
|
||||
|
||||
if (context->NTLMv2)
|
||||
context->UseMIC = TRUE;
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
/*
|
||||
* Extended Protection is enabled by default in Windows 7,
|
||||
* but enabling it in WinPR breaks TS Gateway at this point
|
||||
*/
|
||||
context->SuppressExtendedProtection = FALSE;
|
||||
|
||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("System\\CurrentControlSet\\Control\\LSA"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("SuppressExtendedProtection"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->SuppressExtendedProtection = dwValue ? 1 : 0;
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
context->NegotiateFlags = 0;
|
||||
context->LmCompatibilityLevel = 3;
|
||||
context->state = NTLM_STATE_INITIAL;
|
||||
FillMemory(context->MachineID, sizeof(context->MachineID), 0xAA);
|
||||
|
||||
if (context->NTLMv2)
|
||||
context->UseMIC = TRUE;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
@ -197,10 +247,6 @@ void ntlm_ContextFree(NTLM_CONTEXT* context)
|
||||
sspi_SecBufferFree(&context->LmChallengeResponse);
|
||||
|
||||
free(context->ServicePrincipalName.Buffer);
|
||||
|
||||
free(context->identity.User);
|
||||
free(context->identity.Password);
|
||||
free(context->identity.Domain);
|
||||
free(context->Workstation.Buffer);
|
||||
free(context);
|
||||
}
|
||||
@ -209,39 +255,32 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleW(SEC_WCHAR* pszPrincipal
|
||||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
|
||||
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SEC_WINNT_AUTH_IDENTITY* identity;
|
||||
|
||||
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
|
||||
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_INBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_BOTH))
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
if (identity != NULL)
|
||||
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
}
|
||||
else if (fCredentialUse == SECPKG_CRED_INBOUND)
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
if (identity)
|
||||
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
else
|
||||
ZeroMemory(&(credentials->identity), sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
if (!credentials)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
credentials->fCredentialUse = fCredentialUse;
|
||||
credentials->pGetKeyFn = pGetKeyFn;
|
||||
credentials->pvGetKeyArgument = pvGetKeyArgument;
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
if (identity)
|
||||
sspi_CopyAuthIdentity(&(credentials->identity), identity);
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
@ -250,49 +289,44 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcquireCredentialsHandleA(SEC_CHAR* pszPrincipal,
|
||||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
|
||||
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SEC_WINNT_AUTH_IDENTITY* identity;
|
||||
|
||||
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
|
||||
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_INBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_BOTH))
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
if (identity != NULL)
|
||||
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
}
|
||||
else if (fCredentialUse == SECPKG_CRED_INBOUND)
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
if (identity != NULL)
|
||||
CopyMemory(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
if (!credentials)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
credentials->fCredentialUse = fCredentialUse;
|
||||
credentials->pGetKeyFn = pGetKeyFn;
|
||||
credentials->pvGetKeyArgument = pvGetKeyArgument;
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
if (identity)
|
||||
sspi_CopyAuthIdentity(&(credentials->identity), identity);
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NTLM_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_FreeCredentialsHandle(PCredHandle phCredential)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
if (!phCredential)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
@ -326,7 +360,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P
|
||||
{
|
||||
NTLM_CONTEXT* context;
|
||||
SECURITY_STATUS status;
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
PSecBuffer input_buffer;
|
||||
PSecBuffer output_buffer;
|
||||
|
||||
@ -339,13 +373,13 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P
|
||||
if (!context)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
context->server = 1;
|
||||
context->server = TRUE;
|
||||
|
||||
if (fContextReq & ASC_REQ_CONFIDENTIALITY)
|
||||
context->confidentiality = 1;
|
||||
context->confidentiality = TRUE;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
context->credentials = credentials;
|
||||
|
||||
ntlm_SetContextTargetName(context, NULL);
|
||||
|
||||
@ -414,7 +448,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_AcceptSecurityContext(PCredHandle phCredential, P
|
||||
|
||||
if (pOutput)
|
||||
{
|
||||
int i;
|
||||
ULONG i;
|
||||
|
||||
for (i = 0; i < pOutput->cBuffers; i++)
|
||||
{
|
||||
@ -441,7 +475,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle phCredenti
|
||||
{
|
||||
NTLM_CONTEXT* context;
|
||||
SECURITY_STATUS status;
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
PSecBuffer input_buffer = NULL;
|
||||
PSecBuffer output_buffer = NULL;
|
||||
PSecBuffer channel_bindings = NULL;
|
||||
@ -456,15 +490,19 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextW(PCredHandle phCredenti
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
if (fContextReq & ISC_REQ_CONFIDENTIALITY)
|
||||
context->confidentiality = 1;
|
||||
context->confidentiality = TRUE;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
context->credentials = credentials;
|
||||
|
||||
if (context->Workstation.Length < 1)
|
||||
ntlm_SetContextWorkstation(context, NULL);
|
||||
{
|
||||
if (ntlm_SetContextWorkstation(context, NULL) < 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
ntlm_SetContextServicePrincipalNameW(context, pszTargetName);
|
||||
sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
|
||||
if (ntlm_SetContextServicePrincipalNameW(context, pszTargetName) < 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NTLM_PACKAGE_NAME);
|
||||
@ -554,20 +592,39 @@ SECURITY_STATUS SEC_ENTRY ntlm_InitializeSecurityContextA(PCredHandle phCredenti
|
||||
SECURITY_STATUS status;
|
||||
SEC_WCHAR* pszTargetNameW = NULL;
|
||||
|
||||
if (pszTargetName != NULL)
|
||||
if (pszTargetName)
|
||||
{
|
||||
ConvertToUnicode(CP_UTF8, 0, pszTargetName, -1, &pszTargetNameW, 0);
|
||||
if (ConvertToUnicode(CP_UTF8, 0, pszTargetName, -1, &pszTargetNameW, 0) <= 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
status = ntlm_InitializeSecurityContextW(phCredential, phContext, pszTargetNameW, fContextReq,
|
||||
Reserved1, TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
|
||||
|
||||
if (pszTargetNameW != NULL)
|
||||
if (pszTargetNameW)
|
||||
free(pszTargetNameW);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_CompleteAuthToken(PCtxtHandle phContext, PSecBufferDesc pToken)
|
||||
{
|
||||
NTLM_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (context->server)
|
||||
{
|
||||
status = ntlm_server_AuthenticateComplete(context);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375354 */
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext)
|
||||
@ -588,12 +645,16 @@ SECURITY_STATUS SEC_ENTRY ntlm_DeleteSecurityContext(PCtxtHandle phContext)
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
NTLM_CONTEXT* context;
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (ulAttribute == SECPKG_ATTR_SIZES)
|
||||
{
|
||||
SecPkgContext_Sizes* ContextSizes = (SecPkgContext_Sizes*) pBuffer;
|
||||
@ -605,6 +666,35 @@ SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesW(PCtxtHandle phContext, UL
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
else if (ulAttribute == SECPKG_ATTR_AUTH_IDENTITY)
|
||||
{
|
||||
int status;
|
||||
char* UserA = NULL;
|
||||
char* DomainA = NULL;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SecPkgContext_AuthIdentity* AuthIdentity = (SecPkgContext_AuthIdentity*) pBuffer;
|
||||
|
||||
credentials = context->credentials;
|
||||
ZeroMemory(AuthIdentity, sizeof(SecPkgContext_AuthIdentity));
|
||||
|
||||
UserA = AuthIdentity->User;
|
||||
status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) credentials->identity.User,
|
||||
credentials->identity.UserLength,
|
||||
&UserA, 256, NULL, NULL);
|
||||
|
||||
if (status <= 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
DomainA = AuthIdentity->Domain;
|
||||
status = ConvertFromUnicode(CP_UTF8, 0, (WCHAR*) credentials->identity.Domain,
|
||||
credentials->identity.DomainLength,
|
||||
&DomainA, 256, NULL, NULL);
|
||||
|
||||
if (status <= 0)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
@ -614,6 +704,38 @@ SECURITY_STATUS SEC_ENTRY ntlm_QueryContextAttributesA(PCtxtHandle phContext, UL
|
||||
return ntlm_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
NTLM_CONTEXT* context;
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
|
||||
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (ulAttribute == SECPKG_ATTR_AUTH_NTLM_HASH)
|
||||
{
|
||||
SecPkgContext_AuthNtlmHash* AuthNtlmHash = (SecPkgContext_AuthNtlmHash*) pBuffer;
|
||||
|
||||
if (cbBuffer < sizeof(SecPkgContext_AuthNtlmHash))
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
|
||||
CopyMemory(context->NtlmHash, AuthNtlmHash->NtlmHash, 16);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_SetContextAttributesA(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
return ntlm_SetContextAttributesW(phContext, ulAttribute, pBuffer, cbBuffer);
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_RevertSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
@ -654,20 +776,24 @@ SECURITY_STATUS SEC_ENTRY ntlm_EncryptMessage(PCtxtHandle phContext, ULONG fQOP,
|
||||
/* Copy original data buffer */
|
||||
length = data_buffer->cbBuffer;
|
||||
data = malloc(length);
|
||||
|
||||
if (!data)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
CopyMemory(data, data_buffer->pvBuffer, length);
|
||||
|
||||
/* Compute the HMAC-MD5 hash of ConcatenationOf(seq_num,data) using the client signing key */
|
||||
HMAC_CTX_init(&hmac);
|
||||
HMAC_Init_ex(&hmac, context->SendSigningKey, 16, EVP_md5(), NULL);
|
||||
HMAC_Update(&hmac, (void*) &(SeqNo), 4);
|
||||
HMAC_Update(&hmac, data, length);
|
||||
HMAC_Update(&hmac, (void*) data, length);
|
||||
HMAC_Final(&hmac, digest, NULL);
|
||||
HMAC_CTX_cleanup(&hmac);
|
||||
|
||||
/* Encrypt message using with RC4, result overwrites original buffer */
|
||||
|
||||
if (context->confidentiality)
|
||||
RC4(&context->SendRc4Seal, length, data, data_buffer->pvBuffer);
|
||||
RC4(&context->SendRc4Seal, length, (BYTE*) data, (BYTE*) data_buffer->pvBuffer);
|
||||
else
|
||||
CopyMemory(data_buffer->pvBuffer, data, length);
|
||||
|
||||
@ -719,7 +845,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD
|
||||
PSecBuffer signature_buffer = NULL;
|
||||
|
||||
SeqNo = (UINT32) MessageSeqNo;
|
||||
context = sspi_SecureHandleGetLowerPointer(phContext);
|
||||
context = (NTLM_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
for (index = 0; index < (int) pMessage->cBuffers; index++)
|
||||
{
|
||||
@ -738,12 +864,16 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD
|
||||
/* Copy original data buffer */
|
||||
length = data_buffer->cbBuffer;
|
||||
data = malloc(length);
|
||||
|
||||
if (!data)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
CopyMemory(data, data_buffer->pvBuffer, length);
|
||||
|
||||
/* Decrypt message using with RC4, result overwrites original buffer */
|
||||
|
||||
if (context->confidentiality)
|
||||
RC4(&context->RecvRc4Seal, length, data, data_buffer->pvBuffer);
|
||||
RC4(&context->RecvRc4Seal, length, (BYTE*) data, (BYTE*) data_buffer->pvBuffer);
|
||||
else
|
||||
CopyMemory(data_buffer->pvBuffer, data, length);
|
||||
|
||||
@ -751,7 +881,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD
|
||||
HMAC_CTX_init(&hmac);
|
||||
HMAC_Init_ex(&hmac, context->RecvSigningKey, 16, EVP_md5(), NULL);
|
||||
HMAC_Update(&hmac, (void*) &(SeqNo), 4);
|
||||
HMAC_Update(&hmac, data_buffer->pvBuffer, data_buffer->cbBuffer);
|
||||
HMAC_Update(&hmac, (void*) data_buffer->pvBuffer, data_buffer->cbBuffer);
|
||||
HMAC_Final(&hmac, digest, NULL);
|
||||
HMAC_CTX_cleanup(&hmac);
|
||||
|
||||
@ -784,7 +914,7 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD
|
||||
fprintf(stderr, "Expected Signature:\n");
|
||||
winpr_HexDump(expected_signature, 16);
|
||||
fprintf(stderr, "Actual Signature:\n");
|
||||
winpr_HexDump(signature_buffer->pvBuffer, 16);
|
||||
winpr_HexDump((BYTE*) signature_buffer->pvBuffer, 16);
|
||||
|
||||
return SEC_E_MESSAGE_ALTERED;
|
||||
}
|
||||
@ -794,12 +924,12 @@ SECURITY_STATUS SEC_ENTRY ntlm_DecryptMessage(PCtxtHandle phContext, PSecBufferD
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_MakeSignature(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY ntlm_VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, PULONG pfQOP)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
const SecurityFunctionTableA NTLM_SecurityFunctionTableA =
|
||||
@ -812,7 +942,7 @@ const SecurityFunctionTableA NTLM_SecurityFunctionTableA =
|
||||
NULL, /* Reserved2 */
|
||||
ntlm_InitializeSecurityContextA, /* InitializeSecurityContext */
|
||||
ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
|
||||
NULL, /* CompleteAuthToken */
|
||||
ntlm_CompleteAuthToken, /* CompleteAuthToken */
|
||||
ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
|
||||
NULL, /* ApplyControlToken */
|
||||
ntlm_QueryContextAttributesA, /* QueryContextAttributes */
|
||||
@ -831,7 +961,7 @@ const SecurityFunctionTableA NTLM_SecurityFunctionTableA =
|
||||
NULL, /* QuerySecurityContextToken */
|
||||
ntlm_EncryptMessage, /* EncryptMessage */
|
||||
ntlm_DecryptMessage, /* DecryptMessage */
|
||||
NULL, /* SetContextAttributes */
|
||||
ntlm_SetContextAttributesA, /* SetContextAttributes */
|
||||
};
|
||||
|
||||
const SecurityFunctionTableW NTLM_SecurityFunctionTableW =
|
||||
@ -844,7 +974,7 @@ const SecurityFunctionTableW NTLM_SecurityFunctionTableW =
|
||||
NULL, /* Reserved2 */
|
||||
ntlm_InitializeSecurityContextW, /* InitializeSecurityContext */
|
||||
ntlm_AcceptSecurityContext, /* AcceptSecurityContext */
|
||||
NULL, /* CompleteAuthToken */
|
||||
ntlm_CompleteAuthToken, /* CompleteAuthToken */
|
||||
ntlm_DeleteSecurityContext, /* DeleteSecurityContext */
|
||||
NULL, /* ApplyControlToken */
|
||||
ntlm_QueryContextAttributesW, /* QueryContextAttributes */
|
||||
@ -863,7 +993,7 @@ const SecurityFunctionTableW NTLM_SecurityFunctionTableW =
|
||||
NULL, /* QuerySecurityContextToken */
|
||||
ntlm_EncryptMessage, /* EncryptMessage */
|
||||
ntlm_DecryptMessage, /* DecryptMessage */
|
||||
NULL, /* SetContextAttributes */
|
||||
ntlm_SetContextAttributesA, /* SetContextAttributes */
|
||||
};
|
||||
|
||||
const SecPkgInfoA NTLM_SecPkgInfoA =
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -23,6 +23,8 @@
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/windows.h>
|
||||
|
||||
#include <winpr/nt.h>
|
||||
|
||||
#include <time.h>
|
||||
#include <openssl/des.h>
|
||||
#include <openssl/md4.h>
|
||||
@ -78,6 +80,7 @@ enum _NTLM_STATE
|
||||
NTLM_STATE_NEGOTIATE,
|
||||
NTLM_STATE_CHALLENGE,
|
||||
NTLM_STATE_AUTHENTICATE,
|
||||
NTLM_STATE_COMPLETION,
|
||||
NTLM_STATE_FINAL
|
||||
};
|
||||
typedef enum _NTLM_STATE NTLM_STATE;
|
||||
@ -226,6 +229,8 @@ struct _NTLM_CONTEXT
|
||||
NTLM_STATE state;
|
||||
int SendSeqNum;
|
||||
int RecvSeqNum;
|
||||
BYTE NtlmHash[16];
|
||||
BYTE NtlmV2Hash[16];
|
||||
BYTE MachineID[32];
|
||||
BOOL SendVersionInfo;
|
||||
BOOL confidentiality;
|
||||
@ -241,7 +246,7 @@ struct _NTLM_CONTEXT
|
||||
BOOL SendWorkstationName;
|
||||
UNICODE_STRING Workstation;
|
||||
UNICODE_STRING ServicePrincipalName;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
BYTE* ChannelBindingToken;
|
||||
BYTE ChannelBindingsHash[16];
|
||||
SecPkgContext_Bindings Bindings;
|
||||
@ -258,6 +263,7 @@ struct _NTLM_CONTEXT
|
||||
SecBuffer TargetName;
|
||||
SecBuffer NtChallengeResponse;
|
||||
SecBuffer LmChallengeResponse;
|
||||
NTLMv2_RESPONSE NTLMv2Response;
|
||||
BYTE Timestamp[8];
|
||||
BYTE ChallengeTimestamp[8];
|
||||
BYTE ServerChallenge[8];
|
||||
@ -272,6 +278,7 @@ struct _NTLM_CONTEXT
|
||||
BYTE ServerSigningKey[16];
|
||||
BYTE ServerSealingKey[16];
|
||||
BYTE MessageIntegrityCheck[16];
|
||||
UINT32 MessageIntegrityCheckOffset;
|
||||
};
|
||||
typedef struct _NTLM_CONTEXT NTLM_CONTEXT;
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (AV_PAIRs)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -173,34 +173,45 @@ NTLM_AV_PAIR* ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, NTLM_AV_PAIR* pAv
|
||||
return pAvPairCopy;
|
||||
}
|
||||
|
||||
void ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
|
||||
int ntlm_get_target_computer_name(PUNICODE_STRING pName, COMPUTER_NAME_FORMAT type)
|
||||
{
|
||||
char* name;
|
||||
int length;
|
||||
int status;
|
||||
DWORD nSize = 0;
|
||||
|
||||
GetComputerNameExA(type, NULL, &nSize);
|
||||
name = malloc(nSize);
|
||||
GetComputerNameExA(type, name, &nSize);
|
||||
|
||||
name = (char*) malloc(nSize);
|
||||
|
||||
if (!name)
|
||||
return -1;
|
||||
|
||||
if (!GetComputerNameExA(type, name, &nSize))
|
||||
return -1;
|
||||
|
||||
if (type == ComputerNameNetBIOS)
|
||||
CharUpperA(name);
|
||||
|
||||
length = ConvertToUnicode(CP_UTF8, 0, name, -1, &pName->Buffer, 0);
|
||||
status = ConvertToUnicode(CP_UTF8, 0, name, -1, &pName->Buffer, 0);
|
||||
|
||||
pName->Length = (length - 1) * 2;
|
||||
if (status <= 0)
|
||||
return status;
|
||||
|
||||
pName->Length = (USHORT) ((status - 1) * 2);
|
||||
pName->MaximumLength = pName->Length;
|
||||
|
||||
free(name);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_free_unicode_string(PUNICODE_STRING string)
|
||||
{
|
||||
if (string != NULL)
|
||||
if (string)
|
||||
{
|
||||
if (string->Length > 0)
|
||||
{
|
||||
if (string->Buffer != NULL)
|
||||
if (string->Buffer)
|
||||
free(string->Buffer);
|
||||
|
||||
string->Buffer = NULL;
|
||||
@ -297,7 +308,7 @@ void ntlm_compute_single_host_data(NTLM_CONTEXT* context)
|
||||
FillMemory(context->SingleHostData.MachineID, 32, 0xAA);
|
||||
}
|
||||
|
||||
void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
{
|
||||
int length;
|
||||
ULONG AvPairsCount;
|
||||
@ -310,23 +321,33 @@ void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
UNICODE_STRING DnsComputerName;
|
||||
|
||||
NbDomainName.Buffer = NULL;
|
||||
ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS);
|
||||
|
||||
if (ntlm_get_target_computer_name(&NbDomainName, ComputerNameNetBIOS) < 0)
|
||||
return -1;
|
||||
|
||||
NbComputerName.Buffer = NULL;
|
||||
ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS);
|
||||
|
||||
if (ntlm_get_target_computer_name(&NbComputerName, ComputerNameNetBIOS) < 0)
|
||||
return -1;
|
||||
|
||||
DnsDomainName.Buffer = NULL;
|
||||
ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain);
|
||||
|
||||
if (ntlm_get_target_computer_name(&DnsDomainName, ComputerNameDnsDomain) < 0)
|
||||
return -1;
|
||||
|
||||
DnsComputerName.Buffer = NULL;
|
||||
ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname);
|
||||
|
||||
if (ntlm_get_target_computer_name(&DnsComputerName, ComputerNameDnsHostname) < 0)
|
||||
return -1;
|
||||
|
||||
AvPairsCount = 5;
|
||||
AvPairsLength = NbDomainName.Length + NbComputerName.Length +
|
||||
DnsDomainName.Length + DnsComputerName.Length + 8;
|
||||
|
||||
length = ntlm_av_pair_list_size(AvPairsCount, AvPairsLength);
|
||||
sspi_SecBufferAlloc(&context->ChallengeTargetInfo, length);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&context->ChallengeTargetInfo, length))
|
||||
return -1;
|
||||
|
||||
pAvPairList = (NTLM_AV_PAIR*) context->ChallengeTargetInfo.pvBuffer;
|
||||
AvPairListSize = (ULONG) context->ChallengeTargetInfo.cbBuffer;
|
||||
@ -342,9 +363,11 @@ void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context)
|
||||
ntlm_free_unicode_string(&NbComputerName);
|
||||
ntlm_free_unicode_string(&DnsDomainName);
|
||||
ntlm_free_unicode_string(&DnsComputerName);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
{
|
||||
ULONG size;
|
||||
ULONG AvPairsCount;
|
||||
@ -369,31 +392,31 @@ void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
AvDnsTreeName = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvDnsTreeName);
|
||||
AvTimestamp = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvTimestamp);
|
||||
|
||||
if (AvNbDomainName != NULL)
|
||||
if (AvNbDomainName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvNbDomainName */
|
||||
AvPairsValueLength += AvNbDomainName->AvLen;
|
||||
}
|
||||
|
||||
if (AvNbComputerName != NULL)
|
||||
if (AvNbComputerName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvNbComputerName */
|
||||
AvPairsValueLength += AvNbComputerName->AvLen;
|
||||
}
|
||||
|
||||
if (AvDnsDomainName != NULL)
|
||||
if (AvDnsDomainName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvDnsDomainName */
|
||||
AvPairsValueLength += AvDnsDomainName->AvLen;
|
||||
}
|
||||
|
||||
if (AvDnsComputerName != NULL)
|
||||
if (AvDnsComputerName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvDnsComputerName */
|
||||
AvPairsValueLength += AvDnsComputerName->AvLen;
|
||||
}
|
||||
|
||||
if (AvDnsTreeName != NULL)
|
||||
if (AvDnsTreeName)
|
||||
{
|
||||
AvPairsCount++; /* MsvAvDnsTreeName */
|
||||
AvPairsValueLength += AvDnsTreeName->AvLen;
|
||||
@ -448,22 +471,22 @@ void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
|
||||
ntlm_av_pair_list_init(AuthenticateTargetInfo);
|
||||
|
||||
if (AvNbDomainName != NULL)
|
||||
if (AvNbDomainName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvNbDomainName);
|
||||
|
||||
if (AvNbComputerName != NULL)
|
||||
if (AvNbComputerName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvNbComputerName);
|
||||
|
||||
if (AvDnsDomainName != NULL)
|
||||
if (AvDnsDomainName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsDomainName);
|
||||
|
||||
if (AvDnsComputerName != NULL)
|
||||
if (AvDnsComputerName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsComputerName);
|
||||
|
||||
if (AvDnsTreeName != NULL)
|
||||
if (AvDnsTreeName)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvDnsTreeName);
|
||||
|
||||
if (AvTimestamp != NULL)
|
||||
if (AvTimestamp)
|
||||
ntlm_av_pair_add_copy(AuthenticateTargetInfo, AvTimestamp);
|
||||
|
||||
if (context->UseMIC)
|
||||
@ -497,4 +520,6 @@ void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context)
|
||||
AvEOL = ntlm_av_pair_get(ChallengeTargetInfo, MsvAvEOL);
|
||||
ZeroMemory((void*) AvEOL, 4);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
@ -35,7 +35,7 @@ NTLM_AV_PAIR* ntlm_av_pair_get(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId);
|
||||
NTLM_AV_PAIR* ntlm_av_pair_add(NTLM_AV_PAIR* pAvPairList, NTLM_AV_ID AvId, PBYTE Value, UINT16 AvLen);
|
||||
NTLM_AV_PAIR* ntlm_av_pair_add_copy(NTLM_AV_PAIR* pAvPairList, NTLM_AV_PAIR* pAvPair);
|
||||
|
||||
void ntlm_construct_challenge_target_info(NTLM_CONTEXT* context);
|
||||
void ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context);
|
||||
int ntlm_construct_challenge_target_info(NTLM_CONTEXT* context);
|
||||
int ntlm_construct_authenticate_target_info(NTLM_CONTEXT* context);
|
||||
|
||||
#endif /* WINPR_SSPI_NTLM_AV_PAIRS_H */
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (Compute)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -32,12 +32,15 @@
|
||||
|
||||
#include "ntlm_compute.h"
|
||||
|
||||
const char lm_magic[] = "KGS!@#$%";
|
||||
const char LM_MAGIC[] = "KGS!@#$%";
|
||||
|
||||
static const char client_sign_magic[] = "session key to client-to-server signing key magic constant";
|
||||
static const char server_sign_magic[] = "session key to server-to-client signing key magic constant";
|
||||
static const char client_seal_magic[] = "session key to client-to-server sealing key magic constant";
|
||||
static const char server_seal_magic[] = "session key to server-to-client sealing key magic constant";
|
||||
static const char NTLM_CLIENT_SIGN_MAGIC[] = "session key to client-to-server signing key magic constant";
|
||||
static const char NTLM_SERVER_SIGN_MAGIC[] = "session key to server-to-client signing key magic constant";
|
||||
static const char NTLM_CLIENT_SEAL_MAGIC[] = "session key to client-to-server sealing key magic constant";
|
||||
static const char NTLM_SERVER_SEAL_MAGIC[] = "session key to server-to-client sealing key magic constant";
|
||||
|
||||
static const BYTE NTLM_NULL_HASH[16] =
|
||||
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
|
||||
|
||||
/**
|
||||
* Populate VERSION structure.\n
|
||||
@ -66,13 +69,18 @@ void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo)
|
||||
* @param s
|
||||
*/
|
||||
|
||||
void ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo)
|
||||
{
|
||||
if (Stream_GetRemainingLength(s) < 8)
|
||||
return -1;
|
||||
|
||||
Stream_Read_UINT8(s, versionInfo->ProductMajorVersion); /* ProductMajorVersion (1 byte) */
|
||||
Stream_Read_UINT8(s, versionInfo->ProductMinorVersion); /* ProductMinorVersion (1 byte) */
|
||||
Stream_Read_UINT16(s, versionInfo->ProductBuild); /* ProductBuild (2 bytes) */
|
||||
Stream_Read(s, versionInfo->Reserved, sizeof(versionInfo->Reserved)); /* Reserved (3 bytes) */
|
||||
Stream_Read_UINT8(s, versionInfo->NTLMRevisionCurrent); /* NTLMRevisionCurrent (1 byte) */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -107,7 +115,7 @@ void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo)
|
||||
fprintf(stderr, "\tNTLMRevisionCurrent: 0x%02X\n", versionInfo->NTLMRevisionCurrent);
|
||||
}
|
||||
|
||||
void ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
int ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
{
|
||||
size_t size;
|
||||
|
||||
@ -121,10 +129,16 @@ void ntlm_read_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* cha
|
||||
|
||||
size = Stream_Length(s) - Stream_GetPosition(s);
|
||||
challenge->AvPairs = (NTLM_AV_PAIR*) malloc(size);
|
||||
|
||||
if (!challenge->AvPairs)
|
||||
return -1;
|
||||
|
||||
Stream_Read(s, challenge->AvPairs, size);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
int ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* challenge)
|
||||
{
|
||||
ULONG length;
|
||||
|
||||
@ -138,57 +152,22 @@ void ntlm_write_ntlm_v2_client_challenge(wStream* s, NTLMv2_CLIENT_CHALLENGE* ch
|
||||
|
||||
length = ntlm_av_pair_list_length(challenge->AvPairs);
|
||||
Stream_Write(s, challenge->AvPairs, length);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
{
|
||||
Stream_Read(s, response->Response, 16);
|
||||
ntlm_read_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
return ntlm_read_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
}
|
||||
|
||||
void ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response)
|
||||
{
|
||||
Stream_Write(s, response->Response, 16);
|
||||
ntlm_write_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
return ntlm_write_ntlm_v2_client_challenge(s, &(response->Challenge));
|
||||
}
|
||||
|
||||
#if 0
|
||||
|
||||
/**
|
||||
* Output Restriction_Encoding.\n
|
||||
* Restriction_Encoding @msdn{cc236647}
|
||||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_output_restriction_encoding(NTLM_CONTEXT* context)
|
||||
{
|
||||
wStream* s;
|
||||
AV_PAIR* restrictions = &context->av_pairs->Restrictions;
|
||||
|
||||
BYTE machineID[32] =
|
||||
"\x3A\x15\x8E\xA6\x75\x82\xD8\xF7\x3E\x06\xFA\x7A\xB4\xDF\xFD\x43"
|
||||
"\x84\x6C\x02\x3A\xFD\x5A\x94\xFE\xCF\x97\x0F\x3D\x19\x2C\x38\x20";
|
||||
|
||||
restrictions->value = malloc(48);
|
||||
restrictions->length = 48;
|
||||
|
||||
s = PStreamAllocAttach(restrictions->value, restrictions->length);
|
||||
|
||||
Stream_Write_UINT32(s, 48); /* Size */
|
||||
Stream_Zero(s, 4); /* Z4 (set to zero) */
|
||||
|
||||
/* IntegrityLevel (bit 31 set to 1) */
|
||||
Stream_Write_UINT8(s, 1);
|
||||
Stream_Zero(s, 3);
|
||||
|
||||
Stream_Write_UINT32(s, 0x00002000); /* SubjectIntegrityLevel */
|
||||
Stream_Write(s, machineID, 32); /* MachineID */
|
||||
|
||||
PStreamFreeDetach(s);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Get current time, in tenths of microseconds since midnight of January 1, 1601.
|
||||
* @param[out] timestamp 64-bit little-endian timestamp
|
||||
@ -224,20 +203,22 @@ void ntlm_generate_timestamp(NTLM_CONTEXT* context)
|
||||
ntlm_current_time(context->Timestamp);
|
||||
}
|
||||
|
||||
void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
int ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
WINPR_SAM* sam;
|
||||
WINPR_SAM_ENTRY* entry;
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
|
||||
sam = SamOpen(1);
|
||||
if (sam == NULL)
|
||||
return;
|
||||
sam = SamOpen(TRUE);
|
||||
|
||||
if (!sam)
|
||||
return -1;
|
||||
|
||||
entry = SamLookupUserW(sam,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2);
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2);
|
||||
|
||||
if (entry != NULL)
|
||||
if (entry)
|
||||
{
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
fprintf(stderr, "NTLM Hash:\n");
|
||||
@ -245,20 +226,20 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
#endif
|
||||
|
||||
NTOWFv2FromHashW(entry->NtHash,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2,
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2,
|
||||
(BYTE*) hash);
|
||||
|
||||
SamFreeEntry(sam, entry);
|
||||
SamClose(sam);
|
||||
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
|
||||
entry = SamLookupUserW(sam,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2, NULL, 0);
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2, NULL, 0);
|
||||
|
||||
if (entry != NULL)
|
||||
if (entry)
|
||||
{
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
fprintf(stderr, "NTLM Hash:\n");
|
||||
@ -266,32 +247,44 @@ void ntlm_fetch_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
#endif
|
||||
|
||||
NTOWFv2FromHashW(entry->NtHash,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2,
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2,
|
||||
(BYTE*) hash);
|
||||
|
||||
SamFreeEntry(sam, entry);
|
||||
SamClose(sam);
|
||||
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf(stderr, "Error: Could not find user in SAM database\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
SamClose(sam);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
int ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
int status;
|
||||
int i, hn, ln;
|
||||
char* PasswordHash = NULL;
|
||||
UINT32 PasswordHashLength = 0;
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
|
||||
/* Password contains a password hash of length (PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR) */
|
||||
|
||||
PasswordHashLength = context->identity.PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR;
|
||||
ConvertFromUnicode(CP_UTF8, 0, context->identity.Password, PasswordHashLength, &PasswordHash, 0, NULL, NULL);
|
||||
PasswordHashLength = credentials->identity.PasswordLength / SSPI_CREDENTIALS_HASH_LENGTH_FACTOR;
|
||||
|
||||
status = ConvertFromUnicode(CP_UTF8, 0, (LPCWSTR) credentials->identity.Password,
|
||||
PasswordHashLength, &PasswordHash, 0, NULL, NULL);
|
||||
|
||||
if (status <= 0)
|
||||
return -1;
|
||||
|
||||
CharUpperBuffA(PasswordHash, PasswordHashLength);
|
||||
|
||||
for (i = 0; i < 32; i += 2)
|
||||
@ -302,62 +295,83 @@ void ntlm_convert_password_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
}
|
||||
|
||||
free(PasswordHash);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash)
|
||||
int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash)
|
||||
{
|
||||
if (context->identity.PasswordLength > 256)
|
||||
SSPI_CREDENTIALS* credentials = context->credentials;
|
||||
|
||||
if (memcmp(context->NtlmHash, NTLM_NULL_HASH, 16) != 0)
|
||||
{
|
||||
BYTE PasswordHash[16];
|
||||
|
||||
/* Special case for WinPR: password hash */
|
||||
ntlm_convert_password_hash(context, PasswordHash);
|
||||
|
||||
NTOWFv2FromHashW(PasswordHash,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2,
|
||||
NTOWFv2FromHashW(context->NtlmHash,
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2,
|
||||
(BYTE*) hash);
|
||||
}
|
||||
else if (context->identity.PasswordLength > 0)
|
||||
else if (credentials->identity.PasswordLength > 256)
|
||||
{
|
||||
NTOWFv2W((LPWSTR) context->identity.Password, context->identity.PasswordLength * 2,
|
||||
(LPWSTR) context->identity.User, context->identity.UserLength * 2,
|
||||
(LPWSTR) context->identity.Domain, context->identity.DomainLength * 2, (BYTE*) hash);
|
||||
/* Special case for WinPR: password hash */
|
||||
|
||||
if (ntlm_convert_password_hash(context, context->NtlmHash) < 0)
|
||||
return -1;
|
||||
|
||||
NTOWFv2FromHashW(context->NtlmHash,
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2,
|
||||
(BYTE*) hash);
|
||||
}
|
||||
else if (credentials->identity.PasswordLength > 0)
|
||||
{
|
||||
NTOWFv2W((LPWSTR) credentials->identity.Password, credentials->identity.PasswordLength * 2,
|
||||
(LPWSTR) credentials->identity.User, credentials->identity.UserLength * 2,
|
||||
(LPWSTR) credentials->identity.Domain, credentials->identity.DomainLength * 2, (BYTE*) hash);
|
||||
}
|
||||
else
|
||||
{
|
||||
ntlm_fetch_ntlm_v2_hash(context, hash);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
{
|
||||
char* response;
|
||||
char value[16];
|
||||
char ntlm_v2_hash[16];
|
||||
BYTE* response;
|
||||
BYTE value[16];
|
||||
|
||||
if (context->LmCompatibilityLevel < 2)
|
||||
{
|
||||
sspi_SecBufferAlloc(&context->LmChallengeResponse, 24);
|
||||
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
|
||||
return -1;
|
||||
|
||||
ZeroMemory(context->LmChallengeResponse.pvBuffer, 24);
|
||||
return;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* Compute the NTLMv2 hash */
|
||||
ntlm_compute_ntlm_v2_hash(context, ntlm_v2_hash);
|
||||
|
||||
if (ntlm_compute_ntlm_v2_hash(context, context->NtlmV2Hash) < 0)
|
||||
return -1;
|
||||
|
||||
/* Concatenate the server and client challenges */
|
||||
CopyMemory(value, context->ServerChallenge, 8);
|
||||
CopyMemory(&value[8], context->ClientChallenge, 8);
|
||||
|
||||
sspi_SecBufferAlloc(&context->LmChallengeResponse, 24);
|
||||
response = (char*) context->LmChallengeResponse.pvBuffer;
|
||||
if (!sspi_SecBufferAlloc(&context->LmChallengeResponse, 24))
|
||||
return -1;
|
||||
|
||||
response = (BYTE*) context->LmChallengeResponse.pvBuffer;
|
||||
|
||||
/* Compute the HMAC-MD5 hash of the resulting value using the NTLMv2 hash as the key */
|
||||
HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, (void*) value, 16, (void*) response, NULL);
|
||||
HMAC(EVP_md5(), (void*) context->NtlmV2Hash, 16, (BYTE*) value, 16, (BYTE*) response, NULL);
|
||||
|
||||
/* Concatenate the resulting HMAC-MD5 hash and the client challenge, giving us the LMv2 response (24 bytes) */
|
||||
CopyMemory(&response[16], context->ClientChallenge, 8);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -367,10 +381,9 @@ void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context)
|
||||
* @param NTLM context
|
||||
*/
|
||||
|
||||
void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
{
|
||||
BYTE* blob;
|
||||
BYTE ntlm_v2_hash[16];
|
||||
BYTE nt_proof_str[16];
|
||||
SecBuffer ntlm_v2_temp;
|
||||
SecBuffer ntlm_v2_temp_chal;
|
||||
@ -378,13 +391,16 @@ void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
|
||||
TargetInfo = &context->ChallengeTargetInfo;
|
||||
|
||||
sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28);
|
||||
if (!sspi_SecBufferAlloc(&ntlm_v2_temp, TargetInfo->cbBuffer + 28))
|
||||
return -1;
|
||||
|
||||
ZeroMemory(ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
blob = (BYTE*) ntlm_v2_temp.pvBuffer;
|
||||
|
||||
/* Compute the NTLMv2 hash */
|
||||
ntlm_compute_ntlm_v2_hash(context, (char*) ntlm_v2_hash);
|
||||
|
||||
if (ntlm_compute_ntlm_v2_hash(context, (BYTE*) context->NtlmV2Hash) < 0)
|
||||
return -1;
|
||||
|
||||
#ifdef WITH_DEBUG_NTLM
|
||||
fprintf(stderr, "Password (length = %d)\n", context->identity.PasswordLength * 2);
|
||||
@ -404,7 +420,7 @@ void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
fprintf(stderr, "NTOWFv2, NTLMv2 Hash\n");
|
||||
winpr_HexDump(ntlm_v2_hash, 16);
|
||||
winpr_HexDump(context->NtlmV2Hash, 16);
|
||||
fprintf(stderr, "\n");
|
||||
#endif
|
||||
|
||||
@ -425,25 +441,33 @@ void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context)
|
||||
#endif
|
||||
|
||||
/* Concatenate server challenge with temp */
|
||||
sspi_SecBufferAlloc(&ntlm_v2_temp_chal, ntlm_v2_temp.cbBuffer + 8);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&ntlm_v2_temp_chal, ntlm_v2_temp.cbBuffer + 8))
|
||||
return -1;
|
||||
|
||||
blob = (BYTE*) ntlm_v2_temp_chal.pvBuffer;
|
||||
CopyMemory(blob, context->ServerChallenge, 8);
|
||||
CopyMemory(&blob[8], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
|
||||
HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, ntlm_v2_temp_chal.pvBuffer,
|
||||
ntlm_v2_temp_chal.cbBuffer, (void*) nt_proof_str, NULL);
|
||||
HMAC(EVP_md5(), (BYTE*) context->NtlmV2Hash, 16, (BYTE*) ntlm_v2_temp_chal.pvBuffer,
|
||||
ntlm_v2_temp_chal.cbBuffer, (BYTE*) nt_proof_str, NULL);
|
||||
|
||||
/* NtChallengeResponse, Concatenate NTProofStr with temp */
|
||||
sspi_SecBufferAlloc(&context->NtChallengeResponse, ntlm_v2_temp.cbBuffer + 16);
|
||||
|
||||
if (!sspi_SecBufferAlloc(&context->NtChallengeResponse, ntlm_v2_temp.cbBuffer + 16))
|
||||
return -1;
|
||||
|
||||
blob = (BYTE*) context->NtChallengeResponse.pvBuffer;
|
||||
CopyMemory(blob, nt_proof_str, 16);
|
||||
CopyMemory(&blob[16], ntlm_v2_temp.pvBuffer, ntlm_v2_temp.cbBuffer);
|
||||
|
||||
/* Compute SessionBaseKey, the HMAC-MD5 hash of NTProofStr using the NTLMv2 hash as the key */
|
||||
HMAC(EVP_md5(), (void*) ntlm_v2_hash, 16, (void*) nt_proof_str, 16, (void*) context->SessionBaseKey, NULL);
|
||||
HMAC(EVP_md5(), (BYTE*) context->NtlmV2Hash, 16, (BYTE*) nt_proof_str, 16, (BYTE*) context->SessionBaseKey, NULL);
|
||||
|
||||
sspi_SecBufferFree(&ntlm_v2_temp);
|
||||
sspi_SecBufferFree(&ntlm_v2_temp_chal);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -548,7 +572,7 @@ void ntlm_decrypt_random_session_key(NTLM_CONTEXT* context)
|
||||
* @param signing_key Destination signing key
|
||||
*/
|
||||
|
||||
void ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic, BYTE* signing_key)
|
||||
int ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic, BYTE* signing_key)
|
||||
{
|
||||
int length;
|
||||
BYTE* value;
|
||||
@ -557,6 +581,9 @@ void ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic
|
||||
length = 16 + sign_magic->cbBuffer;
|
||||
value = (BYTE*) malloc(length);
|
||||
|
||||
if (!value)
|
||||
return -1;
|
||||
|
||||
/* Concatenate ExportedSessionKey with sign magic */
|
||||
CopyMemory(value, exported_session_key, 16);
|
||||
CopyMemory(&value[16], sign_magic->pvBuffer, sign_magic->cbBuffer);
|
||||
@ -566,6 +593,8 @@ void ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic
|
||||
MD5_Final(signing_key, &md5);
|
||||
|
||||
free(value);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -576,10 +605,12 @@ void ntlm_generate_signing_key(BYTE* exported_session_key, PSecBuffer sign_magic
|
||||
|
||||
void ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer sign_magic;
|
||||
sign_magic.pvBuffer = (void*) client_sign_magic;
|
||||
sign_magic.cbBuffer = sizeof(client_sign_magic);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sign_magic, context->ClientSigningKey);
|
||||
SecBuffer signMagic;
|
||||
|
||||
signMagic.pvBuffer = (void*) NTLM_CLIENT_SIGN_MAGIC;
|
||||
signMagic.cbBuffer = sizeof(NTLM_CLIENT_SIGN_MAGIC);
|
||||
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ClientSigningKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -590,10 +621,12 @@ void ntlm_generate_client_signing_key(NTLM_CONTEXT* context)
|
||||
|
||||
void ntlm_generate_server_signing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer sign_magic;
|
||||
sign_magic.pvBuffer = (void*) server_sign_magic;
|
||||
sign_magic.cbBuffer = sizeof(server_sign_magic);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sign_magic, context->ServerSigningKey);
|
||||
SecBuffer signMagic;
|
||||
|
||||
signMagic.pvBuffer = (void*) NTLM_SERVER_SIGN_MAGIC;
|
||||
signMagic.cbBuffer = sizeof(NTLM_SERVER_SIGN_MAGIC);
|
||||
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &signMagic, context->ServerSigningKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -604,13 +637,15 @@ void ntlm_generate_server_signing_key(NTLM_CONTEXT* context)
|
||||
* @param sealing_key Destination sealing key
|
||||
*/
|
||||
|
||||
void ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic, BYTE* sealing_key)
|
||||
int ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic, BYTE* sealing_key)
|
||||
{
|
||||
BYTE* p;
|
||||
MD5_CTX md5;
|
||||
SecBuffer buffer;
|
||||
|
||||
sspi_SecBufferAlloc(&buffer, 16 + seal_magic->cbBuffer);
|
||||
if (!sspi_SecBufferAlloc(&buffer, 16 + seal_magic->cbBuffer))
|
||||
return -1;
|
||||
|
||||
p = (BYTE*) buffer.pvBuffer;
|
||||
|
||||
/* Concatenate ExportedSessionKey with seal magic */
|
||||
@ -622,6 +657,8 @@ void ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic
|
||||
MD5_Final(sealing_key, &md5);
|
||||
|
||||
sspi_SecBufferFree(&buffer);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -632,10 +669,12 @@ void ntlm_generate_sealing_key(BYTE* exported_session_key, PSecBuffer seal_magic
|
||||
|
||||
void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer seal_magic;
|
||||
seal_magic.pvBuffer = (void*) client_seal_magic;
|
||||
seal_magic.cbBuffer = sizeof(client_seal_magic);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &seal_magic, context->ClientSealingKey);
|
||||
SecBuffer sealMagic;
|
||||
|
||||
sealMagic.pvBuffer = (void*) NTLM_CLIENT_SEAL_MAGIC;
|
||||
sealMagic.cbBuffer = sizeof(NTLM_CLIENT_SEAL_MAGIC);
|
||||
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ClientSealingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -646,10 +685,12 @@ void ntlm_generate_client_sealing_key(NTLM_CONTEXT* context)
|
||||
|
||||
void ntlm_generate_server_sealing_key(NTLM_CONTEXT* context)
|
||||
{
|
||||
SecBuffer seal_magic;
|
||||
seal_magic.pvBuffer = (void*) server_seal_magic;
|
||||
seal_magic.cbBuffer = sizeof(server_seal_magic);
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &seal_magic, context->ServerSealingKey);
|
||||
SecBuffer sealMagic;
|
||||
|
||||
sealMagic.pvBuffer = (void*) NTLM_SERVER_SEAL_MAGIC;
|
||||
sealMagic.cbBuffer = sizeof(NTLM_SERVER_SEAL_MAGIC);
|
||||
|
||||
ntlm_generate_signing_key(context->ExportedSessionKey, &sealMagic, context->ServerSealingKey);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -690,9 +731,9 @@ void ntlm_compute_message_integrity_check(NTLM_CONTEXT* context)
|
||||
|
||||
HMAC_CTX_init(&hmac_ctx);
|
||||
HMAC_Init_ex(&hmac_ctx, context->ExportedSessionKey, 16, EVP_md5(), NULL);
|
||||
HMAC_Update(&hmac_ctx, context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, (BYTE*) context->NegotiateMessage.pvBuffer, context->NegotiateMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, (BYTE*) context->ChallengeMessage.pvBuffer, context->ChallengeMessage.cbBuffer);
|
||||
HMAC_Update(&hmac_ctx, (BYTE*) context->AuthenticateMessage.pvBuffer, context->AuthenticateMessage.cbBuffer);
|
||||
HMAC_Final(&hmac_ctx, context->MessageIntegrityCheck, NULL);
|
||||
HMAC_CTX_cleanup(&hmac_ctx);
|
||||
}
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (Compute)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -25,24 +25,22 @@
|
||||
#include "ntlm_av_pairs.h"
|
||||
|
||||
void ntlm_get_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
int ntlm_read_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_write_version_info(wStream* s, NTLM_VERSION_INFO* versionInfo);
|
||||
void ntlm_print_version_info(NTLM_VERSION_INFO* versionInfo);
|
||||
|
||||
void ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
void ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
int ntlm_read_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
int ntlm_write_ntlm_v2_response(wStream* s, NTLMv2_RESPONSE* response);
|
||||
|
||||
void ntlm_output_restriction_encoding(NTLM_CONTEXT* context);
|
||||
void ntlm_output_target_name(NTLM_CONTEXT* context);
|
||||
void ntlm_output_channel_bindings(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_current_time(BYTE* timestamp);
|
||||
void ntlm_generate_timestamp(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_compute_ntlm_hash(UINT16* password, UINT32 length, char* hash);
|
||||
void ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, char* hash);
|
||||
void ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
|
||||
void ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
|
||||
int ntlm_compute_ntlm_v2_hash(NTLM_CONTEXT* context, BYTE* hash);
|
||||
int ntlm_compute_lm_v2_response(NTLM_CONTEXT* context);
|
||||
int ntlm_compute_ntlm_v2_response(NTLM_CONTEXT* context);
|
||||
|
||||
void ntlm_rc4k(BYTE* key, int length, BYTE* plaintext, BYTE* ciphertext);
|
||||
void ntlm_generate_client_challenge(NTLM_CONTEXT* context);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* NTLM Security Package (Message)
|
||||
*
|
||||
* Copyright 2011-2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -29,4 +29,6 @@ SECURITY_STATUS ntlm_write_ChallengeMessage(NTLM_CONTEXT* context, PSecBuffer bu
|
||||
SECURITY_STATUS ntlm_read_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer);
|
||||
SECURITY_STATUS ntlm_write_AuthenticateMessage(NTLM_CONTEXT* context, PSecBuffer buffer);
|
||||
|
||||
SECURITY_STATUS ntlm_server_AuthenticateComplete(NTLM_CONTEXT* context);
|
||||
|
||||
#endif /* WINPR_SSPI_NTLM_MESSAGE_H */
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Negotiate Security Package
|
||||
*
|
||||
* Copyright 2011-2012 Jiten Pathy
|
||||
* Copyright 2011-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -28,67 +28,27 @@
|
||||
|
||||
#include "../sspi.h"
|
||||
|
||||
extern const SecurityFunctionTableA NTLM_SecurityFunctionTableA;
|
||||
extern const SecurityFunctionTableW NTLM_SecurityFunctionTableW;
|
||||
|
||||
char* NEGOTIATE_PACKAGE_NAME = "Negotiate";
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(PCredHandle phCredential, PCtxtHandle phContext,
|
||||
SEC_WCHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
|
||||
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextA(PCredHandle phCredential, PCtxtHandle phContext,
|
||||
SEC_CHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
|
||||
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
CREDENTIALS* credentials;
|
||||
PSecBuffer output_SecBuffer;
|
||||
|
||||
context = sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = negotiate_ContextNew();
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
sspi_CopyAuthIdentity(&context->identity, &credentials->identity);
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
if ((!pInput) && (context->state == NEGOTIATE_STATE_INITIAL))
|
||||
{
|
||||
if (!pOutput)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
if (pOutput->cBuffers < 1)
|
||||
return SEC_E_INVALID_TOKEN;
|
||||
|
||||
output_SecBuffer = &pOutput->pBuffers[0];
|
||||
|
||||
if (output_SecBuffer->cbBuffer < 1)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
}
|
||||
|
||||
return SEC_E_OK;
|
||||
|
||||
}
|
||||
|
||||
NEGOTIATE_CONTEXT* negotiate_ContextNew()
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) calloc(1, sizeof(NEGOTIATE_CONTEXT));
|
||||
|
||||
if (context != NULL)
|
||||
{
|
||||
context->NegotiateFlags = 0;
|
||||
context->state = NEGOTIATE_STATE_INITIAL;
|
||||
}
|
||||
if (!context)
|
||||
return NULL;
|
||||
|
||||
context->NegotiateFlags = 0;
|
||||
context->state = NEGOTIATE_STATE_INITIAL;
|
||||
|
||||
SecInvalidateHandle(&(context->SubContext));
|
||||
|
||||
context->sspiA = (SecurityFunctionTableA*) &NTLM_SecurityFunctionTableA;
|
||||
context->sspiW = (SecurityFunctionTableW*) &NTLM_SecurityFunctionTableW;
|
||||
|
||||
return context;
|
||||
}
|
||||
@ -101,21 +61,262 @@ void negotiate_ContextFree(NEGOTIATE_CONTEXT* context)
|
||||
free(context);
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_QueryContextAttributes(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextW(PCredHandle phCredential, PCtxtHandle phContext,
|
||||
SEC_WCHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
|
||||
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = negotiate_ContextNew();
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
status = context->sspiW->InitializeSecurityContextW(phCredential, &(context->SubContext),
|
||||
pszTargetName, fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, &(context->SubContext),
|
||||
pOutput, pfContextAttr, ptsExpiry);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_InitializeSecurityContextA(PCredHandle phCredential, PCtxtHandle phContext,
|
||||
SEC_CHAR* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
|
||||
PSecBufferDesc pInput, ULONG Reserved2, PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsExpiry)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = negotiate_ContextNew();
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
status = context->sspiA->InitializeSecurityContextA(phCredential, &(context->SubContext),
|
||||
pszTargetName, fContextReq, Reserved1, TargetDataRep, pInput, Reserved2, &(context->SubContext),
|
||||
pOutput, pfContextAttr, ptsExpiry);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_AcceptSecurityContext(PCredHandle phCredential, PCtxtHandle phContext,
|
||||
PSecBufferDesc pInput, ULONG fContextReq, ULONG TargetDataRep, PCtxtHandle phNewContext,
|
||||
PSecBufferDesc pOutput, PULONG pfContextAttr, PTimeStamp ptsTimeStamp)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
{
|
||||
context = negotiate_ContextNew();
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phNewContext, context);
|
||||
sspi_SecureHandleSetUpperPointer(phNewContext, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
}
|
||||
|
||||
status = context->sspiA->AcceptSecurityContext(phCredential, &(context->SubContext),
|
||||
pInput, fContextReq, TargetDataRep, &(context->SubContext),
|
||||
pOutput, pfContextAttr, ptsTimeStamp);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_CompleteAuthToken(PCtxtHandle phContext, PSecBufferDesc pToken)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (context->sspiW->CompleteAuthToken)
|
||||
status = context->sspiW->CompleteAuthToken(phContext, pToken);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_DeleteSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!context)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (context->sspiW->DeleteSecurityContext)
|
||||
status = context->sspiW->DeleteSecurityContext(&(context->SubContext));
|
||||
|
||||
negotiate_ContextFree(context);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_ImpersonateSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (context->sspiW->ImpersonateSecurityContext)
|
||||
status = context->sspiW->ImpersonateSecurityContext(&(context->SubContext));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_RevertSecurityContext(PCtxtHandle phContext)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (context->sspiW->RevertSecurityContext)
|
||||
status = context->sspiW->RevertSecurityContext(&(context->SubContext));
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_QueryContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
if (context->sspiW->QueryContextAttributesW)
|
||||
status = context->sspiW->QueryContextAttributesW(&(context->SubContext), ulAttribute, pBuffer);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_QueryContextAttributesA(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
if (context->sspiA->QueryContextAttributesA)
|
||||
status = context->sspiA->QueryContextAttributesA(&(context->SubContext), ulAttribute, pBuffer);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_SetContextAttributesW(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
if (context->sspiW->SetContextAttributesW)
|
||||
status = context->sspiW->SetContextAttributesW(&(context->SubContext), ulAttribute, pBuffer, cbBuffer);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_SetContextAttributesA(PCtxtHandle phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_OK;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (!phContext)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
if (!pBuffer)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
if (context->sspiA->SetContextAttributesA)
|
||||
status = context->sspiA->SetContextAttributesA(&(context->SubContext), ulAttribute, pBuffer, cbBuffer);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_AcquireCredentialsHandleW(SEC_WCHAR* pszPrincipal, SEC_WCHAR* pszPackage,
|
||||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
|
||||
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
|
||||
{
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SEC_WINNT_AUTH_IDENTITY* identity;
|
||||
|
||||
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_INBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_BOTH))
|
||||
{
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
credentials->fCredentialUse = fCredentialUse;
|
||||
credentials->pGetKeyFn = pGetKeyFn;
|
||||
credentials->pvGetKeyArgument = pvGetKeyArgument;
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
if (identity)
|
||||
sspi_CopyAuthIdentity(&(credentials->identity), identity);
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
@ -123,52 +324,54 @@ SECURITY_STATUS SEC_ENTRY negotiate_AcquireCredentialsHandleA(SEC_CHAR* pszPrinc
|
||||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, SEC_GET_KEY_FN pGetKeyFn,
|
||||
void* pvGetKeyArgument, PCredHandle phCredential, PTimeStamp ptsExpiry)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
SEC_WINNT_AUTH_IDENTITY* identity;
|
||||
|
||||
if (fCredentialUse == SECPKG_CRED_OUTBOUND)
|
||||
if ((fCredentialUse != SECPKG_CRED_OUTBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_INBOUND) &&
|
||||
(fCredentialUse != SECPKG_CRED_BOTH))
|
||||
{
|
||||
credentials = sspi_CredentialsNew();
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
memcpy(&(credentials->identity), identity, sizeof(SEC_WINNT_AUTH_IDENTITY));
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
return SEC_E_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
credentials = sspi_CredentialsNew();
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INTERNAL_ERROR;
|
||||
|
||||
credentials->fCredentialUse = fCredentialUse;
|
||||
credentials->pGetKeyFn = pGetKeyFn;
|
||||
credentials->pvGetKeyArgument = pvGetKeyArgument;
|
||||
|
||||
identity = (SEC_WINNT_AUTH_IDENTITY*) pAuthData;
|
||||
|
||||
if (identity)
|
||||
sspi_CopyAuthIdentity(&(credentials->identity), identity);
|
||||
|
||||
sspi_SecureHandleSetLowerPointer(phCredential, (void*) credentials);
|
||||
sspi_SecureHandleSetUpperPointer(phCredential, (void*) NEGOTIATE_PACKAGE_NAME);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_QueryCredentialsAttributesW(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_QueryCredentialsAttributesA(PCredHandle phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
if (ulAttribute == SECPKG_CRED_ATTR_NAMES)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
return SEC_E_OK;
|
||||
}
|
||||
|
||||
return SEC_E_UNSUPPORTED_FUNCTION;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_FreeCredentialsHandle(PCredHandle phCredential)
|
||||
{
|
||||
CREDENTIALS* credentials;
|
||||
SSPI_CREDENTIALS* credentials;
|
||||
|
||||
if (!phCredential)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
|
||||
credentials = (CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
credentials = (SSPI_CREDENTIALS*) sspi_SecureHandleGetLowerPointer(phCredential);
|
||||
|
||||
if (!credentials)
|
||||
return SEC_E_INVALID_HANDLE;
|
||||
@ -180,22 +383,54 @@ SECURITY_STATUS SEC_ENTRY negotiate_FreeCredentialsHandle(PCredHandle phCredenti
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_EncryptMessage(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_UNSUPPORTED_FUNCTION;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (context->sspiW->EncryptMessage)
|
||||
status = context->sspiW->EncryptMessage(&(context->SubContext), fQOP, pMessage, MessageSeqNo);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_DecryptMessage(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_UNSUPPORTED_FUNCTION;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (context->sspiW->DecryptMessage)
|
||||
status = context->sspiW->DecryptMessage(&(context->SubContext), pMessage, MessageSeqNo, pfQOP);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_MakeSignature(PCtxtHandle phContext, ULONG fQOP, PSecBufferDesc pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_UNSUPPORTED_FUNCTION;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (context->sspiW->MakeSignature)
|
||||
status = context->sspiW->MakeSignature(&(context->SubContext), fQOP, pMessage, MessageSeqNo);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
SECURITY_STATUS SEC_ENTRY negotiate_VerifySignature(PCtxtHandle phContext, PSecBufferDesc pMessage, ULONG MessageSeqNo, ULONG* pfQOP)
|
||||
{
|
||||
return SEC_E_OK;
|
||||
NEGOTIATE_CONTEXT* context;
|
||||
SECURITY_STATUS status = SEC_E_UNSUPPORTED_FUNCTION;
|
||||
|
||||
context = (NEGOTIATE_CONTEXT*) sspi_SecureHandleGetLowerPointer(phContext);
|
||||
|
||||
if (context->sspiW->VerifySignature)
|
||||
status = context->sspiW->VerifySignature(&(context->SubContext), pMessage, MessageSeqNo, pfQOP);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
const SecurityFunctionTableA NEGOTIATE_SecurityFunctionTableA =
|
||||
@ -207,13 +442,13 @@ const SecurityFunctionTableA NEGOTIATE_SecurityFunctionTableA =
|
||||
negotiate_FreeCredentialsHandle, /* FreeCredentialsHandle */
|
||||
NULL, /* Reserved2 */
|
||||
negotiate_InitializeSecurityContextA, /* InitializeSecurityContext */
|
||||
NULL, /* AcceptSecurityContext */
|
||||
NULL, /* CompleteAuthToken */
|
||||
NULL, /* DeleteSecurityContext */
|
||||
negotiate_AcceptSecurityContext, /* AcceptSecurityContext */
|
||||
negotiate_CompleteAuthToken, /* CompleteAuthToken */
|
||||
negotiate_DeleteSecurityContext, /* DeleteSecurityContext */
|
||||
NULL, /* ApplyControlToken */
|
||||
negotiate_QueryContextAttributes, /* QueryContextAttributes */
|
||||
NULL, /* ImpersonateSecurityContext */
|
||||
NULL, /* RevertSecurityContext */
|
||||
negotiate_QueryContextAttributesA, /* QueryContextAttributes */
|
||||
negotiate_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
|
||||
negotiate_RevertSecurityContext, /* RevertSecurityContext */
|
||||
negotiate_MakeSignature, /* MakeSignature */
|
||||
negotiate_VerifySignature, /* VerifySignature */
|
||||
NULL, /* FreeContextBuffer */
|
||||
@ -227,7 +462,7 @@ const SecurityFunctionTableA NEGOTIATE_SecurityFunctionTableA =
|
||||
NULL, /* QuerySecurityContextToken */
|
||||
negotiate_EncryptMessage, /* EncryptMessage */
|
||||
negotiate_DecryptMessage, /* DecryptMessage */
|
||||
NULL, /* SetContextAttributes */
|
||||
negotiate_SetContextAttributesA, /* SetContextAttributes */
|
||||
};
|
||||
|
||||
const SecurityFunctionTableW NEGOTIATE_SecurityFunctionTableW =
|
||||
@ -239,13 +474,13 @@ const SecurityFunctionTableW NEGOTIATE_SecurityFunctionTableW =
|
||||
negotiate_FreeCredentialsHandle, /* FreeCredentialsHandle */
|
||||
NULL, /* Reserved2 */
|
||||
negotiate_InitializeSecurityContextW, /* InitializeSecurityContext */
|
||||
NULL, /* AcceptSecurityContext */
|
||||
NULL, /* CompleteAuthToken */
|
||||
NULL, /* DeleteSecurityContext */
|
||||
negotiate_AcceptSecurityContext, /* AcceptSecurityContext */
|
||||
negotiate_CompleteAuthToken, /* CompleteAuthToken */
|
||||
negotiate_DeleteSecurityContext, /* DeleteSecurityContext */
|
||||
NULL, /* ApplyControlToken */
|
||||
negotiate_QueryContextAttributes, /* QueryContextAttributes */
|
||||
NULL, /* ImpersonateSecurityContext */
|
||||
NULL, /* RevertSecurityContext */
|
||||
negotiate_QueryContextAttributesW, /* QueryContextAttributes */
|
||||
negotiate_ImpersonateSecurityContext, /* ImpersonateSecurityContext */
|
||||
negotiate_RevertSecurityContext, /* RevertSecurityContext */
|
||||
negotiate_MakeSignature, /* MakeSignature */
|
||||
negotiate_VerifySignature, /* VerifySignature */
|
||||
NULL, /* FreeContextBuffer */
|
||||
@ -259,7 +494,7 @@ const SecurityFunctionTableW NEGOTIATE_SecurityFunctionTableW =
|
||||
NULL, /* QuerySecurityContextToken */
|
||||
negotiate_EncryptMessage, /* EncryptMessage */
|
||||
negotiate_DecryptMessage, /* DecryptMessage */
|
||||
NULL, /* SetContextAttributes */
|
||||
negotiate_SetContextAttributesW, /* SetContextAttributes */
|
||||
};
|
||||
|
||||
const SecPkgInfoA NEGOTIATE_SecPkgInfoA =
|
||||
|
@ -40,8 +40,12 @@ struct _NEGOTIATE_CONTEXT
|
||||
NEGOTIATE_STATE state;
|
||||
UINT32 NegotiateFlags;
|
||||
PCtxtHandle auth_ctx;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
SecBuffer NegoInitMessage;
|
||||
|
||||
CtxtHandle SubContext;
|
||||
|
||||
SecurityFunctionTableA* sspiA;
|
||||
SecurityFunctionTableW* sspiW;
|
||||
};
|
||||
typedef struct _NEGOTIATE_CONTEXT NEGOTIATE_CONTEXT;
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Schannel Security Package
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Schannel Security Package (OpenSSL)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -280,7 +280,7 @@ SECURITY_STATUS schannel_openssl_client_process_tokens(SCHANNEL_OPENSSL* context
|
||||
|
||||
if (status > 0)
|
||||
{
|
||||
if (pBuffer->cbBuffer < status)
|
||||
if (pBuffer->cbBuffer < (unsigned long) status)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
CopyMemory(pBuffer->pvBuffer, context->ReadBuffer, status);
|
||||
@ -339,7 +339,7 @@ SECURITY_STATUS schannel_openssl_server_process_tokens(SCHANNEL_OPENSSL* context
|
||||
|
||||
if (status > 0)
|
||||
{
|
||||
if (pBuffer->cbBuffer < status)
|
||||
if (pBuffer->cbBuffer < (unsigned long) status)
|
||||
return SEC_E_INSUFFICIENT_MEMORY;
|
||||
|
||||
CopyMemory(pBuffer->pvBuffer, context->ReadBuffer, status);
|
||||
@ -387,17 +387,17 @@ SECURITY_STATUS schannel_openssl_encrypt_message(SCHANNEL_OPENSSL* context, PSec
|
||||
if (status > 0)
|
||||
{
|
||||
offset = 0;
|
||||
length = (pStreamHeaderBuffer->cbBuffer > status) ? status : pStreamHeaderBuffer->cbBuffer;
|
||||
length = (pStreamHeaderBuffer->cbBuffer > (unsigned long) status) ? status : pStreamHeaderBuffer->cbBuffer;
|
||||
CopyMemory(pStreamHeaderBuffer->pvBuffer, &context->ReadBuffer[offset], length);
|
||||
status -= length;
|
||||
|
||||
offset += length;
|
||||
length = (pStreamBodyBuffer->cbBuffer > status) ? status : pStreamBodyBuffer->cbBuffer;
|
||||
length = (pStreamBodyBuffer->cbBuffer > (unsigned long) status) ? status : pStreamBodyBuffer->cbBuffer;
|
||||
CopyMemory(pStreamBodyBuffer->pvBuffer, &context->ReadBuffer[offset], length);
|
||||
status -= length;
|
||||
|
||||
offset += length;
|
||||
length = (pStreamTrailerBuffer->cbBuffer > status) ? status : pStreamTrailerBuffer->cbBuffer;
|
||||
length = (pStreamTrailerBuffer->cbBuffer > (unsigned long) status) ? status : pStreamTrailerBuffer->cbBuffer;
|
||||
CopyMemory(pStreamTrailerBuffer->pvBuffer, &context->ReadBuffer[offset], length);
|
||||
status -= length;
|
||||
}
|
||||
|
@ -1,3 +1,34 @@
|
||||
LIBRARY "libwinpr-sspi"
|
||||
EXPORTS
|
||||
|
||||
AcceptSecurityContext
|
||||
AcquireCredentialsHandleA
|
||||
AcquireCredentialsHandleW
|
||||
ApplyControlToken
|
||||
CompleteAuthToken
|
||||
DecryptMessage
|
||||
DeleteSecurityContext
|
||||
EncryptMessage
|
||||
EnumerateSecurityPackagesA
|
||||
EnumerateSecurityPackagesW
|
||||
ExportSecurityContext
|
||||
FreeContextBuffer
|
||||
FreeCredentialsHandle
|
||||
ImpersonateSecurityContext
|
||||
ImportSecurityContextA
|
||||
ImportSecurityContextW
|
||||
InitSecurityInterfaceA
|
||||
InitSecurityInterfaceW
|
||||
InitializeSecurityContextA
|
||||
InitializeSecurityContextW
|
||||
MakeSignature
|
||||
QueryContextAttributesA
|
||||
QueryContextAttributesW
|
||||
QueryCredentialsAttributesA
|
||||
QueryCredentialsAttributesW
|
||||
QuerySecurityContextToken
|
||||
QuerySecurityPackageInfoA
|
||||
QuerySecurityPackageInfoW
|
||||
RevertSecurityContext
|
||||
VerifySignature
|
||||
InitSecurityInterfaceExA
|
||||
InitSecurityInterfaceExW
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,7 +2,7 @@
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Security Support Provider Interface (SSPI)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -28,20 +28,22 @@
|
||||
|
||||
#define SSPI_CREDENTIALS_HASH_LENGTH_FACTOR 64
|
||||
|
||||
struct _CREDENTIALS
|
||||
struct _SSPI_CREDENTIALS
|
||||
{
|
||||
DWORD flags;
|
||||
ULONG fCredentialUse;
|
||||
SEC_GET_KEY_FN pGetKeyFn;
|
||||
void* pvGetKeyArgument;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
};
|
||||
typedef struct _CREDENTIALS CREDENTIALS;
|
||||
typedef struct _SSPI_CREDENTIALS SSPI_CREDENTIALS;
|
||||
|
||||
CREDENTIALS* sspi_CredentialsNew(void);
|
||||
void sspi_CredentialsFree(CREDENTIALS* credentials);
|
||||
SSPI_CREDENTIALS* sspi_CredentialsNew(void);
|
||||
void sspi_CredentialsFree(SSPI_CREDENTIALS* credentials);
|
||||
|
||||
PSecBuffer sspi_FindSecBuffer(PSecBufferDesc pMessage, ULONG BufferType);
|
||||
|
||||
SecHandle* sspi_SecureHandleAlloc(void);
|
||||
void sspi_SecureHandleInit(SecHandle* handle);
|
||||
void sspi_SecureHandleInvalidate(SecHandle* handle);
|
||||
void* sspi_SecureHandleGetLowerPointer(SecHandle* handle);
|
||||
void sspi_SecureHandleSetLowerPointer(SecHandle* handle, void* pointer);
|
||||
@ -81,4 +83,6 @@ enum SecurityFunctionTableIndex
|
||||
SetContextAttributesIndex = 28
|
||||
};
|
||||
|
||||
#include "sspi_winpr.h"
|
||||
|
||||
#endif /* WINPR_SSPI_PRIVATE_H */
|
||||
|
289
winpr/libwinpr/sspi/sspi_export.c
Normal file
289
winpr/libwinpr/sspi/sspi_export.c
Normal file
@ -0,0 +1,289 @@
|
||||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* Security Support Provider Interface (SSPI)
|
||||
*
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define SEC_ENTRY __stdcall
|
||||
#define SSPI_EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define SEC_ENTRY
|
||||
#define SSPI_EXPORT
|
||||
#endif
|
||||
|
||||
typedef long LONG;
|
||||
typedef unsigned long ULONG;
|
||||
typedef LONG SECURITY_STATUS;
|
||||
|
||||
/**
|
||||
* Standard SSPI API
|
||||
*/
|
||||
|
||||
/* Package Management */
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_EnumerateSecurityPackagesW(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY EnumerateSecurityPackagesW(void* pcPackages, void* ppPackageInfo)
|
||||
{
|
||||
return sspi_EnumerateSecurityPackagesW(pcPackages, ppPackageInfo);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_EnumerateSecurityPackagesA(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY EnumerateSecurityPackagesA(void* pcPackages, void* ppPackageInfo)
|
||||
{
|
||||
return sspi_EnumerateSecurityPackagesA(pcPackages, ppPackageInfo);
|
||||
}
|
||||
|
||||
extern void* SEC_ENTRY sspi_InitSecurityInterfaceW(void);
|
||||
|
||||
SSPI_EXPORT void* SEC_ENTRY InitSecurityInterfaceW(void)
|
||||
{
|
||||
return sspi_InitSecurityInterfaceW();
|
||||
}
|
||||
|
||||
extern void* SEC_ENTRY sspi_InitSecurityInterfaceA(void);
|
||||
|
||||
SSPI_EXPORT void* SEC_ENTRY InitSecurityInterfaceA(void)
|
||||
{
|
||||
return sspi_InitSecurityInterfaceA();
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityPackageInfoW(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QuerySecurityPackageInfoW(void* pszPackageName, void* ppPackageInfo)
|
||||
{
|
||||
return sspi_QuerySecurityPackageInfoW(pszPackageName, ppPackageInfo);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityPackageInfoA(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QuerySecurityPackageInfoA(void* pszPackageName, void* ppPackageInfo)
|
||||
{
|
||||
return sspi_QuerySecurityPackageInfoA(pszPackageName, ppPackageInfo);
|
||||
}
|
||||
|
||||
/* Credential Management */
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_AcquireCredentialsHandleW(void*, void*, ULONG, void*, void*, void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY AcquireCredentialsHandleW(void* pszPrincipal, void* pszPackage,
|
||||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, void* pGetKeyFn,
|
||||
void* pvGetKeyArgument, void* phCredential, void* ptsExpiry)
|
||||
{
|
||||
return sspi_AcquireCredentialsHandleW(pszPrincipal, pszPackage, fCredentialUse,
|
||||
pvLogonID, pAuthData, pGetKeyFn, pvGetKeyArgument, phCredential, ptsExpiry);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_AcquireCredentialsHandleA(void*, void*, ULONG, void*, void*, void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY AcquireCredentialsHandleA(void* pszPrincipal, void* pszPackage,
|
||||
ULONG fCredentialUse, void* pvLogonID, void* pAuthData, void* pGetKeyFn,
|
||||
void* pvGetKeyArgument, void* phCredential, void* ptsExpiry)
|
||||
{
|
||||
return sspi_AcquireCredentialsHandleA(pszPrincipal, pszPackage, fCredentialUse,
|
||||
pvLogonID, pAuthData, pGetKeyFn, pvGetKeyArgument, phCredential, ptsExpiry);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ExportSecurityContext(void*, ULONG, void*, void**);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ExportSecurityContext(void* phContext, ULONG fFlags, void* pPackedContext, void** pToken)
|
||||
{
|
||||
return sspi_ExportSecurityContext(phContext, fFlags, pPackedContext, pToken);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_FreeCredentialsHandle(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY FreeCredentialsHandle(void* phCredential)
|
||||
{
|
||||
return sspi_FreeCredentialsHandle(phCredential);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ImportSecurityContextW(void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ImportSecurityContextW(void* pszPackage, void* pPackedContext, void* pToken, void* phContext)
|
||||
{
|
||||
return sspi_ImportSecurityContextW(pszPackage, pPackedContext, pToken, phContext);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ImportSecurityContextA(void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ImportSecurityContextA(void* pszPackage, void* pPackedContext, void* pToken, void* phContext)
|
||||
{
|
||||
return sspi_ImportSecurityContextA(pszPackage, pPackedContext, pToken, phContext);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QueryCredentialsAttributesW(void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QueryCredentialsAttributesW(void* phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return sspi_QueryCredentialsAttributesW(phCredential, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QueryCredentialsAttributesA(void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QueryCredentialsAttributesA(void* phCredential, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return sspi_QueryCredentialsAttributesA(phCredential, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
/* Context Management */
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_AcceptSecurityContext(void*, void*, void*, ULONG, ULONG, void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY AcceptSecurityContext(void* phCredential, void* phContext,
|
||||
void* pInput, ULONG fContextReq, ULONG TargetDataRep, void* phNewContext,
|
||||
void* pOutput, void* pfContextAttr, void* ptsTimeStamp)
|
||||
{
|
||||
return sspi_AcceptSecurityContext(phCredential, phContext, pInput, fContextReq,
|
||||
TargetDataRep, phNewContext, pOutput, pfContextAttr, ptsTimeStamp);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ApplyControlToken(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ApplyControlToken(void* phContext, void* pInput)
|
||||
{
|
||||
return sspi_ApplyControlToken(phContext, pInput);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_CompleteAuthToken(void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY CompleteAuthToken(void* phContext, void* pToken)
|
||||
{
|
||||
return sspi_CompleteAuthToken(phContext, pToken);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_DeleteSecurityContext(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY DeleteSecurityContext(void* phContext)
|
||||
{
|
||||
return sspi_DeleteSecurityContext(phContext);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_FreeContextBuffer(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY FreeContextBuffer(void* pvContextBuffer)
|
||||
{
|
||||
return sspi_FreeContextBuffer(pvContextBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_ImpersonateSecurityContext(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY ImpersonateSecurityContext(void* phContext)
|
||||
{
|
||||
return sspi_ImpersonateSecurityContext(phContext);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_InitializeSecurityContextW(void*, void*, void*, ULONG, ULONG, ULONG,
|
||||
void*, ULONG, void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY InitializeSecurityContextW(void* phCredential, void* phContext,
|
||||
void* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
|
||||
void* pInput, ULONG Reserved2, void* phNewContext,
|
||||
void* pOutput, void* pfContextAttr, void* ptsExpiry)
|
||||
{
|
||||
return sspi_InitializeSecurityContextW(phCredential, phContext, pszTargetName, fContextReq, Reserved1,
|
||||
TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_InitializeSecurityContextA(void*, void*, void*, ULONG, ULONG, ULONG,
|
||||
void*, ULONG, void*, void*, void*, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY InitializeSecurityContextA(void* phCredential, void* phContext,
|
||||
void* pszTargetName, ULONG fContextReq, ULONG Reserved1, ULONG TargetDataRep,
|
||||
void* pInput, ULONG Reserved2, void* phNewContext,
|
||||
void* pOutput, void* pfContextAttr, void* ptsExpiry)
|
||||
{
|
||||
return sspi_InitializeSecurityContextA(phCredential, phContext, pszTargetName, fContextReq, Reserved1,
|
||||
TargetDataRep, pInput, Reserved2, phNewContext, pOutput, pfContextAttr, ptsExpiry);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QueryContextAttributesW(void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QueryContextAttributesW(void* phContext, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return sspi_QueryContextAttributesW(phContext, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QueryContextAttributesA(void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QueryContextAttributesA(void* phContext, ULONG ulAttribute, void* pBuffer)
|
||||
{
|
||||
return sspi_QueryContextAttributesA(phContext, ulAttribute, pBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_QuerySecurityContextToken(void*, void**);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY QuerySecurityContextToken(void* phContext, void** phToken)
|
||||
{
|
||||
return sspi_QuerySecurityContextToken(phContext, phToken);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_SetContextAttributesW(void*, ULONG, void*, ULONG);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY SetContextAttributesW(void* phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
return sspi_SetContextAttributesW(phContext, ulAttribute, pBuffer, cbBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_SetContextAttributesA(void*, ULONG, void*, ULONG);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY SetContextAttributesA(void* phContext, ULONG ulAttribute, void* pBuffer, ULONG cbBuffer)
|
||||
{
|
||||
return sspi_SetContextAttributesA(phContext, ulAttribute, pBuffer, cbBuffer);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_RevertSecurityContext(void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY RevertSecurityContext(void* phContext)
|
||||
{
|
||||
return sspi_RevertSecurityContext(phContext);
|
||||
}
|
||||
|
||||
/* Message Support */
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_DecryptMessage(void*, void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY DecryptMessage(void* phContext, void* pMessage, ULONG MessageSeqNo, void* pfQOP)
|
||||
{
|
||||
return sspi_DecryptMessage(phContext, pMessage, MessageSeqNo, pfQOP);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_EncryptMessage(void*, ULONG, void*, ULONG);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY EncryptMessage(void* phContext, ULONG fQOP, void* pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return sspi_EncryptMessage(phContext, fQOP, pMessage, MessageSeqNo);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_MakeSignature(void*, ULONG, void*, ULONG);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY MakeSignature(void* phContext, ULONG fQOP, void* pMessage, ULONG MessageSeqNo)
|
||||
{
|
||||
return sspi_MakeSignature(phContext, fQOP, pMessage, MessageSeqNo);
|
||||
}
|
||||
|
||||
extern SECURITY_STATUS SEC_ENTRY sspi_VerifySignature(void*, void*, ULONG, void*);
|
||||
|
||||
SSPI_EXPORT SECURITY_STATUS SEC_ENTRY VerifySignature(void* phContext, void* pMessage, ULONG MessageSeqNo, void* pfQOP)
|
||||
{
|
||||
return sspi_VerifySignature(phContext, pMessage, MessageSeqNo, pfQOP);
|
||||
}
|
1442
winpr/libwinpr/sspi/sspi_winpr.c
Normal file
1442
winpr/libwinpr/sspi/sspi_winpr.c
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,8 +1,8 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* config.h definitions for installable headers
|
||||
* Security Support Provider Interface (SSPI)
|
||||
*
|
||||
* Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
* Copyright 2012-2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
@ -17,16 +17,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_CONFIG_H
|
||||
#define WINPR_CONFIG_H
|
||||
#ifndef WINPR_SSPI_WINPR_H
|
||||
#define WINPR_SSPI_WINPR_H
|
||||
|
||||
/*
|
||||
* This generated config.h header is meant for installation, which is why
|
||||
* all definitions MUST be prefixed to avoid conflicting with third-party
|
||||
* libraries. Only add configurable definitions which really must be used
|
||||
* from installable headers, such as the base type definition types.
|
||||
*/
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
#cmakedefine WITH_NATIVE_SSPI
|
||||
SecurityFunctionTableW* SEC_ENTRY winpr_InitSecurityInterfaceW(void);
|
||||
SecurityFunctionTableA* SEC_ENTRY winpr_InitSecurityInterfaceA(void);
|
||||
|
||||
#endif /* WINPR_CONFIG_H */
|
||||
#endif /* WINPR_SSPI_WINPR_H */
|
@ -9,8 +9,9 @@ set(${MODULE_PREFIX}_TESTS
|
||||
TestEnumerateSecurityPackages.c
|
||||
TestInitializeSecurityContext.c
|
||||
TestAcquireCredentialsHandle.c
|
||||
TestNTLM.c
|
||||
)
|
||||
TestCredSSP.c
|
||||
TestSchannel.c
|
||||
TestNTLM.c)
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS
|
||||
${${MODULE_PREFIX}_DRIVER}
|
||||
|
8
winpr/libwinpr/sspi/test/TestCredSSP.c
Normal file
8
winpr/libwinpr/sspi/test/TestCredSSP.c
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
|
||||
int TestCredSSP(int argc, char* argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
@ -1,59 +1,546 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sspi.h>
|
||||
#include <winpr/print.h>
|
||||
|
||||
BYTE test_Certificate[] =
|
||||
"\x30\x82\x02\x09\x30\x82\x01\x76\xa0\x03\x02\x01\x02\x02\x10\xcb"
|
||||
"\x69\x79\xcd\x51\x75\xc5\xb7\x4b\x67\x30\x83\x6c\x78\x44\x27\x30"
|
||||
"\x09\x06\x05\x2b\x0e\x03\x02\x1d\x05\x00\x30\x16\x31\x14\x30\x12"
|
||||
"\x06\x03\x55\x04\x03\x13\x0b\x44\x43\x2d\x57\x53\x32\x30\x30\x38"
|
||||
"\x52\x32\x30\x1e\x17\x0d\x31\x32\x31\x31\x31\x37\x30\x30\x35\x39"
|
||||
"\x32\x31\x5a\x17\x0d\x33\x39\x31\x32\x33\x31\x32\x33\x35\x39\x35"
|
||||
"\x39\x5a\x30\x16\x31\x14\x30\x12\x06\x03\x55\x04\x03\x13\x0b\x44"
|
||||
"\x43\x2d\x57\x53\x32\x30\x30\x38\x52\x32\x30\x81\x9f\x30\x0d\x06"
|
||||
"\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00"
|
||||
"\x30\x81\x89\x02\x81\x81\x00\x9b\x00\xf8\x1a\x2d\x37\xc6\x8d\xa1"
|
||||
"\x39\x91\x46\xf3\x6a\x1b\xf9\x60\x6c\xb3\x6c\xa0\xac\xed\x85\xe0"
|
||||
"\x3f\xdc\x92\x86\x36\xbd\x64\xbf\x36\x51\xdb\x57\x3a\x8a\x82\x6b"
|
||||
"\xd8\x94\x17\x7b\xd3\x91\x11\x98\xef\x19\x06\x52\x30\x03\x73\x67"
|
||||
"\xc8\xed\x8e\xfa\x0b\x3d\x4c\xc9\x10\x63\x9f\xcf\xb4\xcf\x39\xd8"
|
||||
"\xfe\x99\xeb\x5b\x11\xf2\xfc\xfa\x86\x24\xd9\xff\xd9\x19\xf5\x69"
|
||||
"\xb4\xdf\x5a\x5a\xc4\x94\xb4\xb0\x07\x25\x97\x13\xad\x7e\x38\x14"
|
||||
"\xfb\xd6\x33\x65\x6f\xe6\xf7\x48\x4b\x2d\xb3\x51\x2e\x6d\xc7\xea"
|
||||
"\x11\x76\x9a\x2b\xf0\x00\x4d\x02\x03\x01\x00\x01\xa3\x60\x30\x5e"
|
||||
"\x30\x13\x06\x03\x55\x1d\x25\x04\x0c\x30\x0a\x06\x08\x2b\x06\x01"
|
||||
"\x05\x05\x07\x03\x01\x30\x47\x06\x03\x55\x1d\x01\x04\x40\x30\x3e"
|
||||
"\x80\x10\xeb\x65\x26\x03\x95\x4b\xd6\xc0\x54\x75\x78\x7c\xb6\x2a"
|
||||
"\xa1\xbb\xa1\x18\x30\x16\x31\x14\x30\x12\x06\x03\x55\x04\x03\x13"
|
||||
"\x0b\x44\x43\x2d\x57\x53\x32\x30\x30\x38\x52\x32\x82\x10\xcb\x69"
|
||||
"\x79\xcd\x51\x75\xc5\xb7\x4b\x67\x30\x83\x6c\x78\x44\x27\x30\x09"
|
||||
"\x06\x05\x2b\x0e\x03\x02\x1d\x05\x00\x03\x81\x81\x00\x7b\xfa\xfe"
|
||||
"\xee\x74\x05\xac\xbb\x79\xe9\xda\xca\x00\x44\x96\x94\x71\x92\xb1"
|
||||
"\xdb\xc9\x9b\x71\x29\xc0\xe4\x28\x5e\x6a\x50\x99\xcd\xa8\x17\xe4"
|
||||
"\x56\xb9\xef\x7f\x02\x7d\x96\xa3\x48\x14\x72\x75\x2f\xb0\xb5\x87"
|
||||
"\xee\x55\xe9\x6a\x6d\x28\x3c\xc1\xfd\x00\xe4\x76\xe3\x80\x88\x78"
|
||||
"\x26\x0d\x6c\x8c\xb8\x64\x61\x63\xb7\x13\x3a\xab\xc7\xdd\x1d\x0a"
|
||||
"\xd7\x15\x45\xa1\xd6\xd9\x34\xc7\x21\x48\xfb\x43\x87\x38\xda\x1f"
|
||||
"\x50\x47\xb1\xa5\x5c\x47\xed\x04\x44\x97\xd3\xac\x74\x2d\xeb\x09"
|
||||
"\x77\x59\xbf\xa3\x54\x5b\xde\x42\xd5\x23\x5a\x71\x9f";
|
||||
#define TEST_SSPI_INTERFACE SSPI_INTERFACE_WINPR
|
||||
|
||||
BYTE test_Certificate_SHA256Hash[] =
|
||||
"\xea\x05\xfe\xfe\xcc\x6b\x0b\xd5\x71\xdb\xbc\x5b\xaa\x3e\xd4\x53"
|
||||
"\x86\xd0\x44\x68\x35\xf7\xb7\x4c\x85\x62\x1b\x99\x83\x47\x5f\x95";
|
||||
static const char* TEST_NTLM_USER = "Username";
|
||||
static const char* TEST_NTLM_DOMAIN = "Domain";
|
||||
static const char* TEST_NTLM_PASSWORD = "P4ss123!";
|
||||
|
||||
BYTE test_ChannelBindings_MD5Hash[] =
|
||||
"\x65\x86\xE9\x9D\x81\xC2\xFC\x98\x4E\x47\x17\x2F\xD4\xDD\x03\x10";
|
||||
//static const char* TEST_NTLM_HASH_STRING = "d5922a65c4d5c082ca444af1be0001db";
|
||||
|
||||
int test_ntlm_channel_binding_token()
|
||||
static const BYTE TEST_NTLM_HASH[16] =
|
||||
{ 0xd5, 0x92, 0x2a, 0x65, 0xc4, 0xd5, 0xc0, 0x82, 0xca, 0x44, 0x4a, 0xf1, 0xbe, 0x00, 0x01, 0xdb };
|
||||
|
||||
//#define NTLM_PACKAGE_NAME NEGOSSP_NAME
|
||||
#define NTLM_PACKAGE_NAME NTLMSP_NAME
|
||||
|
||||
struct _TEST_NTLM_CLIENT
|
||||
{
|
||||
CtxtHandle context;
|
||||
ULONG cbMaxToken;
|
||||
ULONG fContextReq;
|
||||
ULONG pfContextAttr;
|
||||
TimeStamp expiration;
|
||||
PSecBuffer pBuffer;
|
||||
SecBuffer inputBuffer[2];
|
||||
SecBuffer outputBuffer[2];
|
||||
BOOL haveContext;
|
||||
BOOL haveInputBuffer;
|
||||
LPTSTR ServicePrincipalName;
|
||||
SecBufferDesc inputBufferDesc;
|
||||
SecBufferDesc outputBufferDesc;
|
||||
CredHandle credentials;
|
||||
BOOL confidentiality;
|
||||
SecPkgInfo* pPackageInfo;
|
||||
SecurityFunctionTable* table;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
};
|
||||
typedef struct _TEST_NTLM_CLIENT TEST_NTLM_CLIENT;
|
||||
|
||||
return 0;
|
||||
int test_ntlm_client_init(TEST_NTLM_CLIENT* ntlm, const char* user, const char* domain, const char* password)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
|
||||
SecInvalidateHandle(&(ntlm->context));
|
||||
|
||||
ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
|
||||
|
||||
sspi_SetAuthIdentity(&(ntlm->identity), user, domain, password);
|
||||
|
||||
status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
fprintf(stderr, "QuerySecurityPackageInfo status: %s (0x%04X)\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
|
||||
|
||||
status = ntlm->table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME,
|
||||
SECPKG_CRED_OUTBOUND, NULL, &ntlm->identity, NULL, NULL, &ntlm->credentials, &ntlm->expiration);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
fprintf(stderr, "AcquireCredentialsHandle status: %s (0x%04X)\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntlm->haveContext = FALSE;
|
||||
ntlm->haveInputBuffer = FALSE;
|
||||
ZeroMemory(&ntlm->inputBuffer, sizeof(SecBuffer));
|
||||
ZeroMemory(&ntlm->outputBuffer, sizeof(SecBuffer));
|
||||
|
||||
ntlm->fContextReq = 0;
|
||||
|
||||
#if 0
|
||||
/* HTTP authentication flags */
|
||||
ntlm->fContextReq |= ISC_REQ_CONFIDENTIALITY;
|
||||
#endif
|
||||
|
||||
/* NLA authentication flags */
|
||||
ntlm->fContextReq |= ISC_REQ_MUTUAL_AUTH;
|
||||
ntlm->fContextReq |= ISC_REQ_CONFIDENTIALITY;
|
||||
ntlm->fContextReq |= ISC_REQ_USE_SESSION_KEY;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void test_ntlm_client_uninit(TEST_NTLM_CLIENT* ntlm)
|
||||
{
|
||||
if (!ntlm)
|
||||
return;
|
||||
|
||||
if (ntlm->outputBuffer[0].pvBuffer)
|
||||
{
|
||||
free(ntlm->outputBuffer[0].pvBuffer);
|
||||
ntlm->outputBuffer[0].pvBuffer = NULL;
|
||||
}
|
||||
|
||||
free(ntlm->identity.User);
|
||||
free(ntlm->identity.Domain);
|
||||
free(ntlm->identity.Password);
|
||||
free(ntlm->ServicePrincipalName);
|
||||
|
||||
if (ntlm->table)
|
||||
{
|
||||
ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
|
||||
ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
|
||||
ntlm->table->DeleteSecurityContext(&ntlm->context);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* SSPI Client Ceremony
|
||||
*
|
||||
* --------------
|
||||
* ( Client Begin )
|
||||
* --------------
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* -----------+--------------
|
||||
* | AcquireCredentialsHandle |
|
||||
* --------------------------
|
||||
* |
|
||||
* |
|
||||
* \|/
|
||||
* -------------+--------------
|
||||
* +---------------> / InitializeSecurityContext /
|
||||
* | ----------------------------
|
||||
* | |
|
||||
* | |
|
||||
* | \|/
|
||||
* --------------------------- ---------+------------- ----------------------
|
||||
* / Receive blob from server / < Received security blob? > --Yes-> / Send blob to server /
|
||||
* -------------+------------- ----------------------- ----------------------
|
||||
* /|\ | |
|
||||
* | No |
|
||||
* Yes \|/ |
|
||||
* | ------------+----------- |
|
||||
* +---------------- < Received Continue Needed > <-----------------+
|
||||
* ------------------------
|
||||
* |
|
||||
* No
|
||||
* \|/
|
||||
* ------+-------
|
||||
* ( Client End )
|
||||
* --------------
|
||||
*/
|
||||
|
||||
int test_ntlm_client_authenticate(TEST_NTLM_CLIENT* ntlm)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
|
||||
if (ntlm->outputBuffer[0].pvBuffer)
|
||||
{
|
||||
free(ntlm->outputBuffer[0].pvBuffer);
|
||||
ntlm->outputBuffer[0].pvBuffer = NULL;
|
||||
}
|
||||
|
||||
ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
ntlm->outputBufferDesc.cBuffers = 1;
|
||||
ntlm->outputBufferDesc.pBuffers = ntlm->outputBuffer;
|
||||
ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
|
||||
ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
|
||||
|
||||
if (!ntlm->outputBuffer[0].pvBuffer)
|
||||
return -1;
|
||||
|
||||
if (ntlm->haveInputBuffer)
|
||||
{
|
||||
ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
ntlm->inputBufferDesc.cBuffers = 1;
|
||||
ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
|
||||
ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
}
|
||||
|
||||
if ((!ntlm) || (!ntlm->table))
|
||||
{
|
||||
fprintf(stderr, "ntlm_authenticate: invalid ntlm context\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = ntlm->table->InitializeSecurityContext(&ntlm->credentials,
|
||||
(ntlm->haveContext) ? &ntlm->context : NULL,
|
||||
(ntlm->ServicePrincipalName) ? ntlm->ServicePrincipalName : NULL,
|
||||
ntlm->fContextReq, 0, SECURITY_NATIVE_DREP,
|
||||
(ntlm->haveInputBuffer) ? &ntlm->inputBufferDesc : NULL,
|
||||
0, &ntlm->context, &ntlm->outputBufferDesc,
|
||||
&ntlm->pfContextAttr, &ntlm->expiration);
|
||||
|
||||
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
|
||||
{
|
||||
if (ntlm->table->CompleteAuthToken)
|
||||
ntlm->table->CompleteAuthToken(&ntlm->context, &ntlm->outputBufferDesc);
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
status = SEC_E_OK;
|
||||
else if (status == SEC_I_COMPLETE_AND_CONTINUE)
|
||||
status = SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
if (ntlm->haveInputBuffer)
|
||||
{
|
||||
free(ntlm->inputBuffer[0].pvBuffer);
|
||||
}
|
||||
|
||||
ntlm->haveInputBuffer = TRUE;
|
||||
ntlm->haveContext = TRUE;
|
||||
|
||||
return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
|
||||
}
|
||||
|
||||
TEST_NTLM_CLIENT* test_ntlm_client_new()
|
||||
{
|
||||
TEST_NTLM_CLIENT* ntlm;
|
||||
|
||||
ntlm = (TEST_NTLM_CLIENT*) calloc(1, sizeof(TEST_NTLM_CLIENT));
|
||||
|
||||
if (!ntlm)
|
||||
return NULL;
|
||||
|
||||
return ntlm;
|
||||
}
|
||||
|
||||
void test_ntlm_client_free(TEST_NTLM_CLIENT* ntlm)
|
||||
{
|
||||
if (!ntlm)
|
||||
return;
|
||||
|
||||
test_ntlm_client_uninit(ntlm);
|
||||
|
||||
free(ntlm);
|
||||
}
|
||||
|
||||
struct _TEST_NTLM_SERVER
|
||||
{
|
||||
CtxtHandle context;
|
||||
ULONG cbMaxToken;
|
||||
ULONG fContextReq;
|
||||
ULONG pfContextAttr;
|
||||
TimeStamp expiration;
|
||||
PSecBuffer pBuffer;
|
||||
SecBuffer inputBuffer[2];
|
||||
SecBuffer outputBuffer[2];
|
||||
BOOL haveContext;
|
||||
BOOL haveInputBuffer;
|
||||
LPTSTR ServicePrincipalName;
|
||||
SecBufferDesc inputBufferDesc;
|
||||
SecBufferDesc outputBufferDesc;
|
||||
CredHandle credentials;
|
||||
BOOL confidentiality;
|
||||
SecPkgInfo* pPackageInfo;
|
||||
SecurityFunctionTable* table;
|
||||
SEC_WINNT_AUTH_IDENTITY identity;
|
||||
};
|
||||
typedef struct _TEST_NTLM_SERVER TEST_NTLM_SERVER;
|
||||
|
||||
int test_ntlm_server_init(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
|
||||
SecInvalidateHandle(&(ntlm->context));
|
||||
|
||||
ntlm->table = InitSecurityInterfaceEx(TEST_SSPI_INTERFACE);
|
||||
|
||||
status = ntlm->table->QuerySecurityPackageInfo(NTLM_PACKAGE_NAME, &ntlm->pPackageInfo);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
fprintf(stderr, "QuerySecurityPackageInfo status: %s (0x%04X)\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntlm->cbMaxToken = ntlm->pPackageInfo->cbMaxToken;
|
||||
|
||||
status = ntlm->table->AcquireCredentialsHandle(NULL, NTLM_PACKAGE_NAME,
|
||||
SECPKG_CRED_INBOUND, NULL, NULL, NULL, NULL,
|
||||
&ntlm->credentials, &ntlm->expiration);
|
||||
|
||||
if (status != SEC_E_OK)
|
||||
{
|
||||
fprintf(stderr, "AcquireCredentialsHandle status: %s (0x%04X)\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ntlm->haveContext = FALSE;
|
||||
ntlm->haveInputBuffer = FALSE;
|
||||
ZeroMemory(&ntlm->inputBuffer, sizeof(SecBuffer));
|
||||
ZeroMemory(&ntlm->outputBuffer, sizeof(SecBuffer));
|
||||
|
||||
ntlm->fContextReq = 0;
|
||||
|
||||
/* NLA authentication flags */
|
||||
ntlm->fContextReq |= ASC_REQ_MUTUAL_AUTH;
|
||||
ntlm->fContextReq |= ASC_REQ_CONFIDENTIALITY;
|
||||
ntlm->fContextReq |= ASC_REQ_CONNECTION;
|
||||
ntlm->fContextReq |= ASC_REQ_USE_SESSION_KEY;
|
||||
ntlm->fContextReq |= ASC_REQ_REPLAY_DETECT;
|
||||
ntlm->fContextReq |= ASC_REQ_SEQUENCE_DETECT;
|
||||
ntlm->fContextReq |= ASC_REQ_EXTENDED_ERROR;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void test_ntlm_server_uninit(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
if (!ntlm)
|
||||
return;
|
||||
|
||||
if (ntlm->outputBuffer[0].pvBuffer)
|
||||
{
|
||||
free(ntlm->outputBuffer[0].pvBuffer);
|
||||
ntlm->outputBuffer[0].pvBuffer = NULL;
|
||||
}
|
||||
|
||||
free(ntlm->identity.User);
|
||||
free(ntlm->identity.Domain);
|
||||
free(ntlm->identity.Password);
|
||||
free(ntlm->ServicePrincipalName);
|
||||
|
||||
if (ntlm->table)
|
||||
{
|
||||
ntlm->table->FreeCredentialsHandle(&ntlm->credentials);
|
||||
ntlm->table->FreeContextBuffer(ntlm->pPackageInfo);
|
||||
ntlm->table->DeleteSecurityContext(&ntlm->context);
|
||||
}
|
||||
}
|
||||
|
||||
int test_ntlm_server_authenticate(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
SECURITY_STATUS status;
|
||||
|
||||
ntlm->inputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
ntlm->inputBufferDesc.cBuffers = 1;
|
||||
ntlm->inputBufferDesc.pBuffers = ntlm->inputBuffer;
|
||||
ntlm->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
|
||||
ntlm->outputBufferDesc.ulVersion = SECBUFFER_VERSION;
|
||||
ntlm->outputBufferDesc.cBuffers = 1;
|
||||
ntlm->outputBufferDesc.pBuffers = &ntlm->outputBuffer[0];
|
||||
ntlm->outputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
ntlm->outputBuffer[0].cbBuffer = ntlm->cbMaxToken;
|
||||
ntlm->outputBuffer[0].pvBuffer = malloc(ntlm->outputBuffer[0].cbBuffer);
|
||||
|
||||
status = ntlm->table->AcceptSecurityContext(&ntlm->credentials,
|
||||
ntlm->haveContext? &ntlm->context: NULL,
|
||||
&ntlm->inputBufferDesc, ntlm->fContextReq, SECURITY_NATIVE_DREP, &ntlm->context,
|
||||
&ntlm->outputBufferDesc, &ntlm->pfContextAttr, &ntlm->expiration);
|
||||
|
||||
if ((status == SEC_I_COMPLETE_AND_CONTINUE) || (status == SEC_I_COMPLETE_NEEDED))
|
||||
{
|
||||
SecPkgContext_AuthIdentity AuthIdentity;
|
||||
SecPkgContext_AuthNtlmHash AuthNtlmHash;
|
||||
|
||||
ZeroMemory(&AuthIdentity, sizeof(SecPkgContext_AuthIdentity));
|
||||
ZeroMemory(&AuthNtlmHash, sizeof(SecPkgContext_AuthNtlmHash));
|
||||
|
||||
status = ntlm->table->QueryContextAttributes(&ntlm->context, SECPKG_ATTR_AUTH_IDENTITY, &AuthIdentity);
|
||||
|
||||
if (status == SEC_E_OK)
|
||||
{
|
||||
if (strcmp(AuthIdentity.User, TEST_NTLM_USER) == 0)
|
||||
{
|
||||
CopyMemory(AuthNtlmHash.NtlmHash, TEST_NTLM_HASH, 16);
|
||||
|
||||
status = ntlm->table->SetContextAttributes(&ntlm->context,
|
||||
SECPKG_ATTR_AUTH_NTLM_HASH, &AuthNtlmHash, sizeof(SecPkgContext_AuthNtlmHash));
|
||||
}
|
||||
}
|
||||
|
||||
if (ntlm->table->CompleteAuthToken)
|
||||
status = ntlm->table->CompleteAuthToken(&ntlm->context, &ntlm->outputBufferDesc);
|
||||
|
||||
if (status == SEC_I_COMPLETE_NEEDED)
|
||||
status = SEC_E_OK;
|
||||
else if (status == SEC_I_COMPLETE_AND_CONTINUE)
|
||||
status = SEC_I_CONTINUE_NEEDED;
|
||||
}
|
||||
|
||||
if ((status != SEC_E_OK) && (status != SEC_I_CONTINUE_NEEDED))
|
||||
{
|
||||
fprintf(stderr, "AcceptSecurityContext status: %s (0x%04X)\n",
|
||||
GetSecurityStatusString(status), status);
|
||||
return -1; /* Access Denied */
|
||||
}
|
||||
|
||||
ntlm->haveContext = TRUE;
|
||||
|
||||
return (status == SEC_I_CONTINUE_NEEDED) ? 1 : 0;
|
||||
}
|
||||
|
||||
TEST_NTLM_SERVER* test_ntlm_server_new()
|
||||
{
|
||||
TEST_NTLM_SERVER* ntlm;
|
||||
|
||||
ntlm = (TEST_NTLM_SERVER*) calloc(1, sizeof(TEST_NTLM_SERVER));
|
||||
|
||||
if (!ntlm)
|
||||
return NULL;
|
||||
|
||||
return ntlm;
|
||||
}
|
||||
|
||||
void test_ntlm_server_free(TEST_NTLM_SERVER* ntlm)
|
||||
{
|
||||
if (!ntlm)
|
||||
return;
|
||||
|
||||
test_ntlm_server_uninit(ntlm);
|
||||
|
||||
free(ntlm);
|
||||
}
|
||||
|
||||
int TestNTLM(int argc, char* argv[])
|
||||
{
|
||||
if (test_ntlm_channel_binding_token() < 0)
|
||||
int status;
|
||||
PSecBuffer pSecBuffer;
|
||||
TEST_NTLM_CLIENT* client;
|
||||
TEST_NTLM_SERVER* server;
|
||||
|
||||
/**
|
||||
* Client Initialization
|
||||
*/
|
||||
|
||||
client = test_ntlm_client_new();
|
||||
|
||||
status = test_ntlm_client_init(client, TEST_NTLM_USER, TEST_NTLM_DOMAIN, TEST_NTLM_PASSWORD);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_client_init failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Server Initialization
|
||||
*/
|
||||
|
||||
server = test_ntlm_server_new();
|
||||
|
||||
status = test_ntlm_server_init(server);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_server_init failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Client -> Negotiate Message
|
||||
*/
|
||||
|
||||
status = test_ntlm_client_authenticate(client);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_client_authenticate failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pSecBuffer = &(client->outputBuffer[0]);
|
||||
|
||||
fprintf(stderr, "NTLM_NEGOTIATE (length = %d):\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
||||
/**
|
||||
* Server <- Negotiate Message
|
||||
* Server -> Challenge Message
|
||||
*/
|
||||
|
||||
server->haveInputBuffer = TRUE;
|
||||
server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
|
||||
server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
|
||||
|
||||
status = test_ntlm_server_authenticate(server);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_server_authenticate failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pSecBuffer = &(server->outputBuffer[0]);
|
||||
|
||||
fprintf(stderr, "NTLM_CHALLENGE (length = %d):\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
||||
/**
|
||||
* Client <- Challenge Message
|
||||
* Client -> Authenticate Message
|
||||
*/
|
||||
|
||||
client->haveInputBuffer = TRUE;
|
||||
client->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
client->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
|
||||
client->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
|
||||
|
||||
status = test_ntlm_client_authenticate(client);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_client_authenticate failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
pSecBuffer = &(client->outputBuffer[0]);
|
||||
|
||||
fprintf(stderr, "NTLM_AUTHENTICATE (length = %d):\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
||||
/**
|
||||
* Server <- Authenticate Message
|
||||
*/
|
||||
|
||||
server->haveInputBuffer = TRUE;
|
||||
server->inputBuffer[0].BufferType = SECBUFFER_TOKEN;
|
||||
server->inputBuffer[0].pvBuffer = pSecBuffer->pvBuffer;
|
||||
server->inputBuffer[0].cbBuffer = pSecBuffer->cbBuffer;
|
||||
|
||||
status = test_ntlm_server_authenticate(server);
|
||||
|
||||
if (status < 0)
|
||||
{
|
||||
printf("test_ntlm_server_authenticate failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup & Termination
|
||||
*/
|
||||
|
||||
test_ntlm_client_free(client);
|
||||
test_ntlm_server_free(server);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -273,7 +273,7 @@ int schannel_send(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phCont
|
||||
|
||||
printf("EncryptMessage status: 0x%08X\n", status);
|
||||
|
||||
printf("EncryptMessage output: cBuffers: %ld [0]: %lu / %lu [1]: %lu / %lu [2]: %lu / %lu [3]: %lu / %lu\n", Message.cBuffers,
|
||||
printf("EncryptMessage output: cBuffers: %d [0]: %u / %u [1]: %u / %u [2]: %u / %u [3]: %u / %u\n", Message.cBuffers,
|
||||
Message.pBuffers[0].cbBuffer, Message.pBuffers[0].BufferType,
|
||||
Message.pBuffers[1].cbBuffer, Message.pBuffers[1].BufferType,
|
||||
Message.pBuffers[2].cbBuffer, Message.pBuffers[2].BufferType,
|
||||
@ -342,7 +342,7 @@ int schannel_recv(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phCont
|
||||
|
||||
printf("DecryptMessage status: 0x%08X\n", status);
|
||||
|
||||
printf("DecryptMessage output: cBuffers: %ld [0]: %lu / %lu [1]: %lu / %lu [2]: %lu / %lu [3]: %lu / %lu\n", Message.cBuffers,
|
||||
printf("DecryptMessage output: cBuffers: %d [0]: %u / %u [1]: %u / %u [2]: %u / %u [3]: %u / %u\n", Message.cBuffers,
|
||||
Message.pBuffers[0].cbBuffer, Message.pBuffers[0].BufferType,
|
||||
Message.pBuffers[1].cbBuffer, Message.pBuffers[1].BufferType,
|
||||
Message.pBuffers[2].cbBuffer, Message.pBuffers[2].BufferType,
|
||||
@ -351,7 +351,7 @@ int schannel_recv(PSecurityFunctionTable table, HANDLE hPipe, PCtxtHandle phCont
|
||||
if (status != SEC_E_OK)
|
||||
return -1;
|
||||
|
||||
printf("Decrypted Message (%ld)\n", Message.pBuffers[1].cbBuffer);
|
||||
printf("Decrypted Message (%d)\n", Message.pBuffers[1].cbBuffer);
|
||||
winpr_HexDump((BYTE*) Message.pBuffers[1].pvBuffer, Message.pBuffers[1].cbBuffer);
|
||||
|
||||
if (memcmp(Message.pBuffers[1].pvBuffer, test_LastDummyMessage, sizeof(test_LastDummyMessage)) == 0)
|
||||
@ -522,9 +522,9 @@ static void* schannel_test_server_thread(void* arg)
|
||||
else if (status == SEC_E_INCOMPLETE_MESSAGE)
|
||||
printf("AcceptSecurityContext status: SEC_E_INCOMPLETE_MESSAGE\n");
|
||||
|
||||
printf("Server cBuffers: %lu pBuffers[0]: %lu type: %lu\n",
|
||||
printf("Server cBuffers: %u pBuffers[0]: %u type: %u\n",
|
||||
SecBufferDesc_out.cBuffers, SecBufferDesc_out.pBuffers[0].cbBuffer, SecBufferDesc_out.pBuffers[0].BufferType);
|
||||
printf("Server Input cBuffers: %ld pBuffers[0]: %lu type: %lu pBuffers[1]: %lu type: %lu\n", SecBufferDesc_in.cBuffers,
|
||||
printf("Server Input cBuffers: %d pBuffers[0]: %u type: %u pBuffers[1]: %u type: %u\n", SecBufferDesc_in.cBuffers,
|
||||
SecBufferDesc_in.pBuffers[0].cbBuffer, SecBufferDesc_in.pBuffers[0].BufferType,
|
||||
SecBufferDesc_in.pBuffers[1].cbBuffer, SecBufferDesc_in.pBuffers[1].BufferType);
|
||||
|
||||
@ -543,7 +543,7 @@ static void* schannel_test_server_thread(void* arg)
|
||||
|
||||
if (pSecBuffer->cbBuffer > 0)
|
||||
{
|
||||
printf("Server > Client (%ld)\n", pSecBuffer->cbBuffer);
|
||||
printf("Server > Client (%d)\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
||||
if (!WriteFile(g_ClientWritePipe, pSecBuffer->pvBuffer, pSecBuffer->cbBuffer, &NumberOfBytesWritten, NULL))
|
||||
@ -615,7 +615,7 @@ int dump_test_certificate_files()
|
||||
int TestSchannel(int argc, char* argv[])
|
||||
{
|
||||
int count;
|
||||
int index;
|
||||
DWORD index;
|
||||
ALG_ID algId;
|
||||
HANDLE thread;
|
||||
BYTE* lpTokenIn;
|
||||
@ -641,6 +641,8 @@ int TestSchannel(int argc, char* argv[])
|
||||
SecPkgCred_CipherStrengths CipherStrengths;
|
||||
SecPkgCred_SupportedProtocols SupportedProtocols;
|
||||
|
||||
return 0; /* disable by default - causes crash */
|
||||
|
||||
sspi_GlobalInit();
|
||||
|
||||
dump_test_certificate_files();
|
||||
@ -713,7 +715,7 @@ int TestSchannel(int argc, char* argv[])
|
||||
* 0x800C 0x800D 0x800E 0x2400 0xAA02 0xAE06 0x2200 0x2203
|
||||
*/
|
||||
|
||||
printf("SupportedAlgs: %ld\n", SupportedAlgs.cSupportedAlgs);
|
||||
printf("SupportedAlgs: %d\n", SupportedAlgs.cSupportedAlgs);
|
||||
|
||||
for (index = 0; index < SupportedAlgs.cSupportedAlgs; index++)
|
||||
{
|
||||
@ -734,7 +736,7 @@ int TestSchannel(int argc, char* argv[])
|
||||
|
||||
/* CipherStrengths: Minimum: 40 Maximum: 256 */
|
||||
|
||||
printf("CipherStrengths: Minimum: %ld Maximum: %ld\n",
|
||||
printf("CipherStrengths: Minimum: %d Maximum: %d\n",
|
||||
CipherStrengths.dwMinimumCipherStrength, CipherStrengths.dwMaximumCipherStrength);
|
||||
|
||||
ZeroMemory(&SupportedProtocols, sizeof(SecPkgCred_SupportedProtocols));
|
||||
@ -748,7 +750,7 @@ int TestSchannel(int argc, char* argv[])
|
||||
|
||||
/* SupportedProtocols: 0x208A0 */
|
||||
|
||||
printf("SupportedProtocols: 0x%04lX\n", SupportedProtocols.grbitProtocol);
|
||||
printf("SupportedProtocols: 0x%04X\n", SupportedProtocols.grbitProtocol);
|
||||
|
||||
fContextReq = ISC_REQ_STREAM |
|
||||
ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
|
||||
@ -781,7 +783,7 @@ int TestSchannel(int argc, char* argv[])
|
||||
}
|
||||
|
||||
g_ClientWait = TRUE;
|
||||
printf("NumberOfBytesRead: %ld\n", NumberOfBytesRead);
|
||||
printf("NumberOfBytesRead: %d\n", NumberOfBytesRead);
|
||||
|
||||
SecBuffer_in[0].BufferType = SECBUFFER_TOKEN;
|
||||
SecBuffer_in[0].pvBuffer = lpTokenIn;
|
||||
@ -821,9 +823,9 @@ int TestSchannel(int argc, char* argv[])
|
||||
else if (status == SEC_E_INCOMPLETE_MESSAGE)
|
||||
printf("InitializeSecurityContext status: SEC_E_INCOMPLETE_MESSAGE\n");
|
||||
|
||||
printf("Client Output cBuffers: %ld pBuffers[0]: %ld type: %ld\n",
|
||||
printf("Client Output cBuffers: %d pBuffers[0]: %d type: %d\n",
|
||||
SecBufferDesc_out.cBuffers, SecBufferDesc_out.pBuffers[0].cbBuffer, SecBufferDesc_out.pBuffers[0].BufferType);
|
||||
printf("Client Input cBuffers: %ld pBuffers[0]: %ld type: %ld pBuffers[1]: %ld type: %ld\n", SecBufferDesc_in.cBuffers,
|
||||
printf("Client Input cBuffers: %d pBuffers[0]: %d type: %d pBuffers[1]: %d type: %d\n", SecBufferDesc_in.cBuffers,
|
||||
SecBufferDesc_in.pBuffers[0].cbBuffer, SecBufferDesc_in.pBuffers[0].BufferType,
|
||||
SecBufferDesc_in.pBuffers[1].cbBuffer, SecBufferDesc_in.pBuffers[1].BufferType);
|
||||
|
||||
@ -833,7 +835,7 @@ int TestSchannel(int argc, char* argv[])
|
||||
|
||||
if (pSecBuffer->cbBuffer > 0)
|
||||
{
|
||||
printf("Client > Server (%ld)\n", pSecBuffer->cbBuffer);
|
||||
printf("Client > Server (%d)\n", pSecBuffer->cbBuffer);
|
||||
winpr_HexDump((BYTE*) pSecBuffer->pvBuffer, pSecBuffer->cbBuffer);
|
||||
|
||||
if (!WriteFile(g_ServerWritePipe, pSecBuffer->pvBuffer, pSecBuffer->cbBuffer, &NumberOfBytesWritten, NULL))
|
||||
|
@ -59,7 +59,11 @@ BOOL TzSpecificLocalTimeToSystemTime(LPTIME_ZONE_INFORMATION lpTimeZoneInformati
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0600)) /* Windows Vista */
|
||||
/*
|
||||
* GetDynamicTimeZoneInformation is provided by the SDK if _WIN32_WINNT >= 0x0600 in SDKs above 7.1A
|
||||
* and incorrectly if _WIN32_WINNT >= 0x0501 in older SDKs
|
||||
*/
|
||||
#if !defined(_WIN32) || (defined(_WIN32) && (defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0600 || !defined(NTDDI_WIN8) && _WIN32_WINNT < 0x0501)) /* Windows Vista */
|
||||
|
||||
DWORD GetDynamicTimeZoneInformation(PDYNAMIC_TIME_ZONE_INFORMATION pTimeZoneInformation)
|
||||
{
|
||||
|
@ -285,7 +285,11 @@ BOOL ArrayList_Remove(wArrayList* arrayList, void* obj)
|
||||
}
|
||||
|
||||
if (found)
|
||||
{
|
||||
if (arrayList->object.fnObjectFree)
|
||||
arrayList->object.fnObjectFree(arrayList->array[index]);
|
||||
ret = ArrayList_Shift(arrayList, index, -1);
|
||||
}
|
||||
|
||||
if (arrayList->synchronized)
|
||||
LeaveCriticalSection(&arrayList->lock);
|
||||
@ -305,6 +309,8 @@ BOOL ArrayList_RemoveAt(wArrayList* arrayList, int index)
|
||||
|
||||
if ((index >= 0) && (index < arrayList->size))
|
||||
{
|
||||
if (arrayList->object.fnObjectFree)
|
||||
arrayList->object.fnObjectFree(arrayList->array[index]);
|
||||
ret = ArrayList_Shift(arrayList, index, -1);
|
||||
}
|
||||
|
||||
|
@ -319,7 +319,7 @@ int WLog_ParseFilters()
|
||||
{
|
||||
char* p;
|
||||
char* env;
|
||||
int count;
|
||||
DWORD count;
|
||||
DWORD nSize;
|
||||
int status;
|
||||
char** strs;
|
||||
|
Loading…
Reference in New Issue
Block a user