Blame server/shadow/shadow_server.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2014 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
Packit 1fb8d4
 * Copyright 2017 Thincast Technologies GmbH
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <errno.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/ssl.h>
Packit 1fb8d4
#include <winpr/wnd.h>
Packit 1fb8d4
#include <winpr/path.h>
Packit 1fb8d4
#include <winpr/cmdline.h>
Packit 1fb8d4
#include <winpr/winsock.h>
Packit 1fb8d4
Packit 1fb8d4
#include <freerdp/log.h>
Packit 1fb8d4
#include <freerdp/version.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/tools/makecert.h>
Packit 1fb8d4
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
#include <sys/select.h>
Packit 1fb8d4
#include <signal.h>
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include "shadow.h"
Packit 1fb8d4
Packit 1fb8d4
#define TAG SERVER_TAG("shadow")
Packit 1fb8d4
Packit 1fb8d4
static COMMAND_LINE_ARGUMENT_A shadow_args[] =
Packit 1fb8d4
{
Packit 1fb8d4
	{ "port", COMMAND_LINE_VALUE_REQUIRED, "<number>", NULL, NULL, -1, NULL, "Server port" },
Packit 1fb8d4
	{ "ipc-socket", COMMAND_LINE_VALUE_REQUIRED, "<ipc-socket>", NULL, NULL, -1, NULL, "Server IPC socket" },
Packit 1fb8d4
	{ "monitors", COMMAND_LINE_VALUE_OPTIONAL, "<0,1,2...>", NULL, NULL, -1, NULL, "Select or list monitors" },
Packit 1fb8d4
	{ "rect", COMMAND_LINE_VALUE_REQUIRED, "<x,y,w,h>", NULL, NULL, -1, NULL, "Select rectangle within monitor to share" },
Packit 1fb8d4
	{ "auth", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "Clients must authenticate" },
Packit 1fb8d4
	{ "may-view", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Clients may view without prompt" },
Packit 1fb8d4
	{ "may-interact", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "Clients may interact without prompt" },
Packit 1fb8d4
	{ "sec", COMMAND_LINE_VALUE_REQUIRED, "<rdp|tls|nla|ext>", NULL, NULL, -1, NULL, "force specific protocol security" },
Packit 1fb8d4
	{ "sec-rdp", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "rdp protocol security" },
Packit 1fb8d4
	{ "sec-tls", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "tls protocol security" },
Packit 1fb8d4
	{ "sec-nla", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueTrue, NULL, -1, NULL, "nla protocol security" },
Packit 1fb8d4
	{ "sec-ext", COMMAND_LINE_VALUE_BOOL, NULL, BoolValueFalse, NULL, -1, NULL, "nla extended protocol security" },
Packit 1fb8d4
	{ "sam-file", COMMAND_LINE_VALUE_REQUIRED, "<file>", NULL, NULL, -1, NULL, "NTLM SAM file for NLA authentication" },
Packit 1fb8d4
	{ "version", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_VERSION, NULL, NULL, NULL, -1, NULL, "Print version" },
Packit 1fb8d4
	{ "help", COMMAND_LINE_VALUE_FLAG | COMMAND_LINE_PRINT_HELP, NULL, NULL, NULL, -1, "?", "Print help" },
Packit 1fb8d4
	{ NULL, 0, NULL, NULL, NULL, -1, NULL, NULL }
Packit 1fb8d4
};
Packit 1fb8d4
Packit 1fb8d4
static int shadow_server_print_command_line_help(int argc, char** argv)
Packit 1fb8d4
{
Packit 1fb8d4
	char* str;
Packit 1fb8d4
	int length;
Packit 1fb8d4
	COMMAND_LINE_ARGUMENT_A* arg;
Packit 1fb8d4
	WLog_INFO(TAG, "Usage: %s [options]", argv[0]);
Packit 1fb8d4
	WLog_INFO(TAG, "");
Packit 1fb8d4
	WLog_INFO(TAG, "Syntax:");
Packit 1fb8d4
	WLog_INFO(TAG, "    /flag (enables flag)");
Packit 1fb8d4
	WLog_INFO(TAG, "    /option:<value> (specifies option with value)");
Packit 1fb8d4
	WLog_INFO(TAG, "    +toggle -toggle (enables or disables toggle, where '/' is a synonym of '+')");
Packit 1fb8d4
	WLog_INFO(TAG, "");
Packit 1fb8d4
	arg = shadow_args;
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		if (arg->Flags & COMMAND_LINE_VALUE_FLAG)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_INFO(TAG, "    %s", "/");
Packit 1fb8d4
			WLog_INFO(TAG, "%-20s", arg->Name);
Packit 1fb8d4
			WLog_INFO(TAG, "\t%s", arg->Text);
Packit 1fb8d4
		}
Packit 1fb8d4
		else if ((arg->Flags & COMMAND_LINE_VALUE_REQUIRED) || (arg->Flags & COMMAND_LINE_VALUE_OPTIONAL))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_INFO(TAG, "    %s", "/");
Packit 1fb8d4
Packit 1fb8d4
			if (arg->Format)
Packit 1fb8d4
			{
Packit 1fb8d4
				length = (int)(strlen(arg->Name) + strlen(arg->Format) + 2);
Packit 1fb8d4
				str = (char*) malloc(length + 1);
Packit 1fb8d4
Packit 1fb8d4
				if (!str)
Packit 1fb8d4
					return -1;
Packit 1fb8d4
Packit 1fb8d4
				sprintf_s(str, length + 1, "%s:%s", arg->Name, arg->Format);
Packit 1fb8d4
				WLog_INFO(TAG, "%-20s", str);
Packit 1fb8d4
				free(str);
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_INFO(TAG, "%-20s", arg->Name);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			WLog_INFO(TAG, "\t%s", arg->Text);
Packit 1fb8d4
		}
Packit 1fb8d4
		else if (arg->Flags & COMMAND_LINE_VALUE_BOOL)
Packit 1fb8d4
		{
Packit 1fb8d4
			length = (int) strlen(arg->Name) + 32;
Packit 1fb8d4
			str = (char*) malloc(length + 1);
Packit 1fb8d4
Packit 1fb8d4
			if (!str)
Packit 1fb8d4
				return -1;
Packit 1fb8d4
Packit 1fb8d4
			sprintf_s(str, length + 1, "%s (default:%s)", arg->Name,
Packit 1fb8d4
			          arg->Default ? "on" : "off");
Packit 1fb8d4
			WLog_INFO(TAG, "    %s", arg->Default ? "-" : "+");
Packit 1fb8d4
			WLog_INFO(TAG, "%-20s", str);
Packit 1fb8d4
			free(str);
Packit 1fb8d4
			WLog_INFO(TAG, "\t%s", arg->Text);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
	while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int shadow_server_command_line_status_print(rdpShadowServer* server, int argc, char** argv,
Packit 1fb8d4
        int status)
Packit 1fb8d4
{
Packit 1fb8d4
	if (status == COMMAND_LINE_STATUS_PRINT_VERSION)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_INFO(TAG, "FreeRDP version %s (git %s)", FREERDP_VERSION_FULL, GIT_REVISION);
Packit 1fb8d4
		return COMMAND_LINE_STATUS_PRINT_VERSION;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (status == COMMAND_LINE_STATUS_PRINT)
Packit 1fb8d4
	{
Packit 1fb8d4
		return COMMAND_LINE_STATUS_PRINT;
Packit 1fb8d4
	}
Packit 1fb8d4
	else if (status < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (shadow_server_print_command_line_help(argc, argv) < 0)
Packit 1fb8d4
			return -1;
Packit 1fb8d4
Packit 1fb8d4
		return COMMAND_LINE_STATUS_PRINT_HELP;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int shadow_server_parse_command_line(rdpShadowServer* server, int argc, char** argv)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	DWORD flags;
Packit 1fb8d4
	COMMAND_LINE_ARGUMENT_A* arg;
Packit 1fb8d4
	rdpSettings* settings = server->settings;
Packit 1fb8d4
Packit 1fb8d4
	if (argc < 2)
Packit 1fb8d4
		return 1;
Packit 1fb8d4
Packit 1fb8d4
	CommandLineClearArgumentsA(shadow_args);
Packit 1fb8d4
	flags = COMMAND_LINE_SEPARATOR_COLON;
Packit 1fb8d4
	flags |= COMMAND_LINE_SIGIL_SLASH | COMMAND_LINE_SIGIL_PLUS_MINUS;
Packit 1fb8d4
	status = CommandLineParseArgumentsA(argc, argv, shadow_args, flags, server, NULL,
Packit 1fb8d4
	                                    NULL);
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
		return status;
Packit 1fb8d4
Packit 1fb8d4
	arg = shadow_args;
Packit 1fb8d4
	errno = 0;
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!(arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
Packit 1fb8d4
			continue;
Packit 1fb8d4
Packit 1fb8d4
		CommandLineSwitchStart(arg)
Packit 1fb8d4
		CommandLineSwitchCase(arg, "port")
Packit 1fb8d4
		{
Packit 1fb8d4
			long val = strtol(arg->Value, NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
			if ((errno != 0) || (val <= 0) || (val > UINT16_MAX))
Packit 1fb8d4
				return -1;
Packit 1fb8d4
Packit 1fb8d4
			server->port = (DWORD) val;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "ipc-socket")
Packit 1fb8d4
		{
Packit 1fb8d4
			server->ipcSocket = _strdup(arg->Value);
Packit 1fb8d4
Packit 1fb8d4
			if (!server->ipcSocket)
Packit 1fb8d4
				return -1;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "may-view")
Packit 1fb8d4
		{
Packit 1fb8d4
			server->mayView = arg->Value ? TRUE : FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "may-interact")
Packit 1fb8d4
		{
Packit 1fb8d4
			server->mayInteract = arg->Value ? TRUE : FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "rect")
Packit 1fb8d4
		{
Packit 1fb8d4
			char* p;
Packit 1fb8d4
			char* tok[4];
Packit 1fb8d4
			long x = -1, y = -1, w = -1, h = -1;
Packit 1fb8d4
			char* str = _strdup(arg->Value);
Packit 1fb8d4
Packit 1fb8d4
			if (!str)
Packit 1fb8d4
				return -1;
Packit 1fb8d4
Packit 1fb8d4
			tok[0] = p = str;
Packit 1fb8d4
			p = strchr(p + 1, ',');
Packit 1fb8d4
Packit 1fb8d4
			if (!p)
Packit 1fb8d4
			{
Packit 1fb8d4
				free(str);
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			*p++ = '\0';
Packit 1fb8d4
			tok[1] = p;
Packit 1fb8d4
			p = strchr(p + 1, ',');
Packit 1fb8d4
Packit 1fb8d4
			if (!p)
Packit 1fb8d4
			{
Packit 1fb8d4
				free(str);
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			*p++ = '\0';
Packit 1fb8d4
			tok[2] = p;
Packit 1fb8d4
			p = strchr(p + 1, ',');
Packit 1fb8d4
Packit 1fb8d4
			if (!p)
Packit 1fb8d4
			{
Packit 1fb8d4
				free(str);
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			*p++ = '\0';
Packit 1fb8d4
			tok[3] = p;
Packit 1fb8d4
			x = strtol(tok[0], NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
			if (errno != 0)
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
Packit 1fb8d4
			y = strtol(tok[1], NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
			if (errno != 0)
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
Packit 1fb8d4
			w = strtol(tok[2], NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
			if (errno != 0)
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
Packit 1fb8d4
			h = strtol(tok[3], NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
			if (errno != 0)
Packit 1fb8d4
				goto fail;
Packit 1fb8d4
Packit 1fb8d4
		fail:
Packit 1fb8d4
			free(str);
Packit 1fb8d4
Packit 1fb8d4
			if ((x < 0) || (y < 0) || (w < 1) || (h < 1) || (errno != 0))
Packit 1fb8d4
				return -1;
Packit 1fb8d4
Packit 1fb8d4
			server->subRect.left = x;
Packit 1fb8d4
			server->subRect.top = y;
Packit 1fb8d4
			server->subRect.right = x + w;
Packit 1fb8d4
			server->subRect.bottom = y + h;
Packit 1fb8d4
			server->shareSubRect = TRUE;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "auth")
Packit 1fb8d4
		{
Packit 1fb8d4
			server->authentication = arg->Value ? TRUE : FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "sec")
Packit 1fb8d4
		{
Packit 1fb8d4
			if (strcmp("rdp", arg->Value) == 0) /* Standard RDP */
Packit 1fb8d4
			{
Packit 1fb8d4
				settings->RdpSecurity = TRUE;
Packit 1fb8d4
				settings->TlsSecurity = FALSE;
Packit 1fb8d4
				settings->NlaSecurity = FALSE;
Packit 1fb8d4
				settings->ExtSecurity = FALSE;
Packit 1fb8d4
				settings->UseRdpSecurityLayer = TRUE;
Packit 1fb8d4
			}
Packit 1fb8d4
			else if (strcmp("tls", arg->Value) == 0) /* TLS */
Packit 1fb8d4
			{
Packit 1fb8d4
				settings->RdpSecurity = FALSE;
Packit 1fb8d4
				settings->TlsSecurity = TRUE;
Packit 1fb8d4
				settings->NlaSecurity = FALSE;
Packit 1fb8d4
				settings->ExtSecurity = FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
			else if (strcmp("nla", arg->Value) == 0) /* NLA */
Packit 1fb8d4
			{
Packit 1fb8d4
				settings->RdpSecurity = FALSE;
Packit 1fb8d4
				settings->TlsSecurity = FALSE;
Packit 1fb8d4
				settings->NlaSecurity = TRUE;
Packit 1fb8d4
				settings->ExtSecurity = FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
			else if (strcmp("ext", arg->Value) == 0) /* NLA Extended */
Packit 1fb8d4
			{
Packit 1fb8d4
				settings->RdpSecurity = FALSE;
Packit 1fb8d4
				settings->TlsSecurity = FALSE;
Packit 1fb8d4
				settings->NlaSecurity = FALSE;
Packit 1fb8d4
				settings->ExtSecurity = TRUE;
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "unknown protocol security: %s", arg->Value);
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "sec-rdp")
Packit 1fb8d4
		{
Packit 1fb8d4
			settings->RdpSecurity = arg->Value ? TRUE : FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "sec-tls")
Packit 1fb8d4
		{
Packit 1fb8d4
			settings->TlsSecurity = arg->Value ? TRUE : FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "sec-nla")
Packit 1fb8d4
		{
Packit 1fb8d4
			settings->NlaSecurity = arg->Value ? TRUE : FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "sec-ext")
Packit 1fb8d4
		{
Packit 1fb8d4
			settings->ExtSecurity = arg->Value ? TRUE : FALSE;
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchCase(arg, "sam-file")
Packit 1fb8d4
		{
Packit 1fb8d4
			freerdp_set_param_string(settings, FreeRDP_NtlmSamFile, arg->Value);
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchDefault(arg)
Packit 1fb8d4
		{
Packit 1fb8d4
		}
Packit 1fb8d4
		CommandLineSwitchEnd(arg)
Packit 1fb8d4
	}
Packit 1fb8d4
	while ((arg = CommandLineFindNextArgumentA(arg)) != NULL);
Packit 1fb8d4
Packit 1fb8d4
	arg = CommandLineFindArgumentA(shadow_args, "monitors");
Packit 1fb8d4
Packit 1fb8d4
	if (arg && (arg->Flags & COMMAND_LINE_ARGUMENT_PRESENT))
Packit 1fb8d4
	{
Packit 1fb8d4
		int index;
Packit 1fb8d4
		int numMonitors;
Packit 1fb8d4
		MONITOR_DEF monitors[16];
Packit 1fb8d4
		numMonitors = shadow_enum_monitors(monitors, 16);
Packit 1fb8d4
Packit 1fb8d4
		if (arg->Flags & COMMAND_LINE_VALUE_PRESENT)
Packit 1fb8d4
		{
Packit 1fb8d4
			/* Select monitors */
Packit 1fb8d4
			long val = strtol(arg->Value, NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
			if ((val < 0) || (errno != 0) || (val >= numMonitors))
Packit 1fb8d4
				status = COMMAND_LINE_STATUS_PRINT;
Packit 1fb8d4
Packit 1fb8d4
			server->selectedMonitor = val;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit 1fb8d4
			int width, height;
Packit 1fb8d4
			MONITOR_DEF* monitor;
Packit 1fb8d4
Packit 1fb8d4
			/* List monitors */
Packit 1fb8d4
Packit 1fb8d4
			for (index = 0; index < numMonitors; index++)
Packit 1fb8d4
			{
Packit 1fb8d4
				monitor = &monitors[index];
Packit 1fb8d4
				width = monitor->right - monitor->left;
Packit 1fb8d4
				height = monitor->bottom - monitor->top;
Packit 1fb8d4
				WLog_INFO(TAG, "      %s [%d] %dx%d\t+%"PRId32"+%"PRId32"",
Packit 1fb8d4
				          (monitor->flags == 1) ? "*" : " ", index,
Packit 1fb8d4
				          width, height, monitor->left, monitor->top);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			status = COMMAND_LINE_STATUS_PRINT;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static DWORD WINAPI shadow_server_thread(LPVOID arg)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpShadowServer* server = (rdpShadowServer*)arg;
Packit 1fb8d4
	BOOL running = TRUE;
Packit 1fb8d4
	DWORD status;
Packit 1fb8d4
	freerdp_listener* listener = server->listener;
Packit 1fb8d4
	shadow_subsystem_start(server->subsystem);
Packit 1fb8d4
Packit 1fb8d4
	while (running)
Packit 1fb8d4
	{
Packit 1fb8d4
		HANDLE events[32];
Packit 1fb8d4
		DWORD nCount = 0;
Packit 1fb8d4
		events[nCount++] = server->StopEvent;
Packit 1fb8d4
		nCount += listener->GetEventHandles(listener, &events[nCount], 32 - nCount);
Packit 1fb8d4
Packit 1fb8d4
		if (nCount <= 1)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to get FreeRDP file descriptor");
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		status = WaitForMultipleObjects(nCount, events, FALSE, INFINITE);
Packit 1fb8d4
Packit 1fb8d4
		switch (status)
Packit 1fb8d4
		{
Packit 1fb8d4
			case WAIT_FAILED:
Packit 1fb8d4
			case WAIT_OBJECT_0:
Packit 1fb8d4
				running = FALSE;
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			default:
Packit 1fb8d4
				{
Packit 1fb8d4
					if (!listener->CheckFileDescriptor(listener))
Packit 1fb8d4
					{
Packit 1fb8d4
						WLog_ERR(TAG, "Failed to check FreeRDP file descriptor");
Packit 1fb8d4
						running = FALSE;
Packit 1fb8d4
					}
Packit 1fb8d4
					else
Packit 1fb8d4
					{
Packit 1fb8d4
#ifdef _WIN32
Packit 1fb8d4
						Sleep(100); /* FIXME: listener event handles */
Packit 1fb8d4
#endif
Packit 1fb8d4
					}
Packit 1fb8d4
				}
Packit 1fb8d4
				break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	listener->Close(listener);
Packit 1fb8d4
	shadow_subsystem_stop(server->subsystem);
Packit 1fb8d4
Packit 1fb8d4
	/* Signal to the clients that server is being stopped and wait for them
Packit 1fb8d4
	 * to disconnect. */
Packit 1fb8d4
	if (shadow_client_boardcast_quit(server, 0))
Packit 1fb8d4
	{
Packit 1fb8d4
		while (ArrayList_Count(server->clients) > 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			Sleep(100);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ExitThread(0);
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int shadow_server_start(rdpShadowServer* server)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
	WSADATA wsaData;
Packit 1fb8d4
Packit 1fb8d4
	if (!server)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
#ifndef _WIN32
Packit 1fb8d4
	signal(SIGPIPE, SIG_IGN);
Packit 1fb8d4
#endif
Packit 1fb8d4
	server->screen = shadow_screen_new(server);
Packit 1fb8d4
Packit 1fb8d4
	if (!server->screen)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "screen_new failed");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	server->capture = shadow_capture_new(server);
Packit 1fb8d4
Packit 1fb8d4
	if (!server->capture)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "capture_new failed");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!server->ipcSocket)
Packit 1fb8d4
		status = server->listener->Open(server->listener, NULL, (UINT16) server->port);
Packit 1fb8d4
	else
Packit 1fb8d4
		status = server->listener->OpenLocal(server->listener, server->ipcSocket);
Packit 1fb8d4
Packit 1fb8d4
	if (!status)
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Problem creating listener. (Port already used or insufficient permissions?)");
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!(server->thread = CreateThread(NULL, 0, shadow_server_thread, (void*) server, 0, NULL)))
Packit 1fb8d4
	{
Packit 1fb8d4
		return -1;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int shadow_server_stop(rdpShadowServer* server)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!server)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (server->thread)
Packit 1fb8d4
	{
Packit 1fb8d4
		SetEvent(server->StopEvent);
Packit 1fb8d4
		WaitForSingleObject(server->thread, INFINITE);
Packit 1fb8d4
		CloseHandle(server->thread);
Packit 1fb8d4
		server->thread = NULL;
Packit 1fb8d4
		server->listener->Close(server->listener);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (server->screen)
Packit 1fb8d4
	{
Packit 1fb8d4
		shadow_screen_free(server->screen);
Packit 1fb8d4
		server->screen = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (server->capture)
Packit 1fb8d4
	{
Packit 1fb8d4
		shadow_capture_free(server->capture);
Packit 1fb8d4
		server->capture = NULL;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return 0;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static int shadow_server_init_config_path(rdpShadowServer* server)
Packit 1fb8d4
{
Packit 1fb8d4
#ifdef _WIN32
Packit 1fb8d4
Packit 1fb8d4
	if (!server->ConfigPath)
Packit 1fb8d4
	{
Packit 1fb8d4
		server->ConfigPath = GetEnvironmentSubPath("LOCALAPPDATA", "freerdp");
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
#ifdef __APPLE__
Packit 1fb8d4
Packit 1fb8d4
	if (!server->ConfigPath)
Packit 1fb8d4
	{
Packit 1fb8d4
		char* userLibraryPath;
Packit 1fb8d4
		char* userApplicationSupportPath;
Packit 1fb8d4
		userLibraryPath = GetKnownSubPath(KNOWN_PATH_HOME, "Library");
Packit 1fb8d4
Packit 1fb8d4
		if (userLibraryPath)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!PathFileExistsA(userLibraryPath) &&
Packit 1fb8d4
			    !PathMakePathA(userLibraryPath, 0))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Failed to create directory '%s'", userLibraryPath);
Packit 1fb8d4
				free(userLibraryPath);
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			userApplicationSupportPath = GetCombinedPath(userLibraryPath, "Application Support");
Packit 1fb8d4
Packit 1fb8d4
			if (userApplicationSupportPath)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (!PathFileExistsA(userApplicationSupportPath) &&
Packit 1fb8d4
				    !PathMakePathA(userApplicationSupportPath, 0))
Packit 1fb8d4
				{
Packit 1fb8d4
					WLog_ERR(TAG, "Failed to create directory '%s'", userApplicationSupportPath);
Packit 1fb8d4
					free(userLibraryPath);
Packit 1fb8d4
					free(userApplicationSupportPath);
Packit 1fb8d4
					return -1;
Packit 1fb8d4
				}
Packit 1fb8d4
Packit 1fb8d4
				server->ConfigPath = GetCombinedPath(userApplicationSupportPath, "freerdp");
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			free(userLibraryPath);
Packit 1fb8d4
			free(userApplicationSupportPath);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
	if (!server->ConfigPath)
Packit 1fb8d4
	{
Packit 1fb8d4
		char* configHome;
Packit 1fb8d4
		configHome = GetKnownPath(KNOWN_PATH_XDG_CONFIG_HOME);
Packit 1fb8d4
Packit 1fb8d4
		if (configHome)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!PathFileExistsA(configHome) &&
Packit 1fb8d4
			    !PathMakePathA(configHome, 0))
Packit 1fb8d4
			{
Packit 1fb8d4
				WLog_ERR(TAG, "Failed to create directory '%s'", configHome);
Packit 1fb8d4
				free(configHome);
Packit 1fb8d4
				return -1;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			server->ConfigPath = GetKnownSubPath(KNOWN_PATH_XDG_CONFIG_HOME, "freerdp");
Packit 1fb8d4
			free(configHome);
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!server->ConfigPath)
Packit 1fb8d4
		return -1; /* no usable config path */
Packit 1fb8d4
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL shadow_server_init_certificate(rdpShadowServer* server)
Packit 1fb8d4
{
Packit 1fb8d4
	char* filepath;
Packit 1fb8d4
	MAKECERT_CONTEXT* makecert = NULL;
Packit 1fb8d4
	BOOL ret = FALSE;
Packit 1fb8d4
	const char* makecert_argv[6] =
Packit 1fb8d4
	{
Packit 1fb8d4
		"makecert",
Packit 1fb8d4
		"-rdp",
Packit 1fb8d4
		"-live",
Packit 1fb8d4
		"-silent",
Packit 1fb8d4
		"-y", "5"
Packit 1fb8d4
	};
Packit 1fb8d4
	int makecert_argc = (sizeof(makecert_argv) / sizeof(char*));
Packit 1fb8d4
Packit 1fb8d4
	if (!PathFileExistsA(server->ConfigPath) &&
Packit 1fb8d4
	    !PathMakePathA(server->ConfigPath, 0))
Packit 1fb8d4
	{
Packit 1fb8d4
		WLog_ERR(TAG, "Failed to create directory '%s'", server->ConfigPath);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!(filepath = GetCombinedPath(server->ConfigPath, "shadow")))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!PathFileExistsA(filepath) &&
Packit 1fb8d4
	    !PathMakePathA(filepath, 0))
Packit 1fb8d4
	{
Packit 1fb8d4
		if (!CreateDirectoryA(filepath, 0))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_ERR(TAG, "Failed to create directory '%s'", filepath);
Packit 1fb8d4
			goto out_fail;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	server->CertificateFile = GetCombinedPath(filepath, "shadow.crt");
Packit 1fb8d4
	server->PrivateKeyFile = GetCombinedPath(filepath, "shadow.key");
Packit 1fb8d4
Packit 1fb8d4
	if (!server->CertificateFile || !server->PrivateKeyFile)
Packit 1fb8d4
		goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
	if ((!PathFileExistsA(server->CertificateFile)) ||
Packit 1fb8d4
	    (!PathFileExistsA(server->PrivateKeyFile)))
Packit 1fb8d4
	{
Packit 1fb8d4
		makecert = makecert_context_new();
Packit 1fb8d4
Packit 1fb8d4
		if (!makecert)
Packit 1fb8d4
			goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
		if (makecert_context_process(makecert, makecert_argc, (char**) makecert_argv) < 0)
Packit 1fb8d4
			goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
		if (makecert_context_set_output_file_name(makecert, "shadow") != 1)
Packit 1fb8d4
			goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
		if (!PathFileExistsA(server->CertificateFile))
Packit 1fb8d4
		{
Packit 1fb8d4
			if (makecert_context_output_certificate_file(makecert, filepath) != 1)
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (!PathFileExistsA(server->PrivateKeyFile))
Packit 1fb8d4
		{
Packit 1fb8d4
			if (makecert_context_output_private_key_file(makecert, filepath) != 1)
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	ret = TRUE;
Packit 1fb8d4
out_fail:
Packit 1fb8d4
	makecert_context_free(makecert);
Packit 1fb8d4
	free(filepath);
Packit 1fb8d4
	return ret;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int shadow_server_init(rdpShadowServer* server)
Packit 1fb8d4
{
Packit 1fb8d4
	int status;
Packit 1fb8d4
	winpr_InitializeSSL(WINPR_SSL_INIT_DEFAULT);
Packit 1fb8d4
	WTSRegisterWtsApiFunctionTable(FreeRDP_InitWtsApi());
Packit 1fb8d4
Packit 1fb8d4
	if (!(server->clients = ArrayList_New(TRUE)))
Packit 1fb8d4
		goto fail_client_array;
Packit 1fb8d4
Packit 1fb8d4
	if (!(server->StopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
Packit 1fb8d4
		goto fail_stop_event;
Packit 1fb8d4
Packit 1fb8d4
	if (!InitializeCriticalSectionAndSpinCount(&(server->lock), 4000))
Packit 1fb8d4
		goto fail_server_lock;
Packit 1fb8d4
Packit 1fb8d4
	status = shadow_server_init_config_path(server);
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
		goto fail_config_path;
Packit 1fb8d4
Packit 1fb8d4
	status = shadow_server_init_certificate(server);
Packit 1fb8d4
Packit 1fb8d4
	if (status < 0)
Packit 1fb8d4
		goto fail_certificate;
Packit 1fb8d4
Packit 1fb8d4
	server->listener = freerdp_listener_new();
Packit 1fb8d4
Packit 1fb8d4
	if (!server->listener)
Packit 1fb8d4
		goto fail_listener;
Packit 1fb8d4
Packit 1fb8d4
	server->listener->info = (void*) server;
Packit 1fb8d4
	server->listener->PeerAccepted = shadow_client_accepted;
Packit 1fb8d4
	server->subsystem = shadow_subsystem_new();
Packit 1fb8d4
Packit 1fb8d4
	if (!server->subsystem)
Packit 1fb8d4
		goto fail_subsystem_new;
Packit 1fb8d4
Packit 1fb8d4
	status = shadow_subsystem_init(server->subsystem, server);
Packit 1fb8d4
Packit 1fb8d4
	if (status >= 0)
Packit 1fb8d4
		return status;
Packit 1fb8d4
Packit 1fb8d4
	shadow_subsystem_free(server->subsystem);
Packit 1fb8d4
fail_subsystem_new:
Packit 1fb8d4
	freerdp_listener_free(server->listener);
Packit 1fb8d4
	server->listener = NULL;
Packit 1fb8d4
fail_listener:
Packit 1fb8d4
	free(server->CertificateFile);
Packit 1fb8d4
	server->CertificateFile = NULL;
Packit 1fb8d4
	free(server->PrivateKeyFile);
Packit 1fb8d4
	server->PrivateKeyFile = NULL;
Packit 1fb8d4
fail_certificate:
Packit 1fb8d4
	free(server->ConfigPath);
Packit 1fb8d4
	server->ConfigPath = NULL;
Packit 1fb8d4
fail_config_path:
Packit 1fb8d4
	DeleteCriticalSection(&(server->lock));
Packit 1fb8d4
fail_server_lock:
Packit 1fb8d4
	CloseHandle(server->StopEvent);
Packit 1fb8d4
	server->StopEvent = NULL;
Packit 1fb8d4
fail_stop_event:
Packit 1fb8d4
	ArrayList_Free(server->clients);
Packit 1fb8d4
	server->clients = NULL;
Packit 1fb8d4
fail_client_array:
Packit 1fb8d4
	WLog_ERR(TAG, "Failed to initialize shadow server");
Packit 1fb8d4
	return -1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int shadow_server_uninit(rdpShadowServer* server)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!server)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	shadow_server_stop(server);
Packit 1fb8d4
	shadow_subsystem_uninit(server->subsystem);
Packit 1fb8d4
	shadow_subsystem_free(server->subsystem);
Packit 1fb8d4
	freerdp_listener_free(server->listener);
Packit 1fb8d4
	server->listener = NULL;
Packit 1fb8d4
	free(server->CertificateFile);
Packit 1fb8d4
	server->CertificateFile = NULL;
Packit 1fb8d4
	free(server->PrivateKeyFile);
Packit 1fb8d4
	server->PrivateKeyFile = NULL;
Packit 1fb8d4
	free(server->ConfigPath);
Packit 1fb8d4
	server->ConfigPath = NULL;
Packit 1fb8d4
	DeleteCriticalSection(&(server->lock));
Packit 1fb8d4
	CloseHandle(server->StopEvent);
Packit 1fb8d4
	server->StopEvent = NULL;
Packit 1fb8d4
	ArrayList_Free(server->clients);
Packit 1fb8d4
	server->clients = NULL;
Packit 1fb8d4
	return 1;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
rdpShadowServer* shadow_server_new(void)
Packit 1fb8d4
{
Packit 1fb8d4
	rdpShadowServer* server;
Packit 1fb8d4
	server = (rdpShadowServer*) calloc(1, sizeof(rdpShadowServer));
Packit 1fb8d4
Packit 1fb8d4
	if (!server)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	server->port = 3389;
Packit 1fb8d4
	server->mayView = TRUE;
Packit 1fb8d4
	server->mayInteract = TRUE;
Packit 1fb8d4
	server->rfxMode = RLGR3;
Packit 1fb8d4
	server->h264RateControlMode = H264_RATECONTROL_VBR;
Packit 1fb8d4
	server->h264BitRate = 10000000;
Packit 1fb8d4
	server->h264FrameRate = 30;
Packit 1fb8d4
	server->h264QP = 0;
Packit 1fb8d4
	server->authentication = FALSE;
Packit 1fb8d4
	server->settings = freerdp_settings_new(FREERDP_SETTINGS_SERVER_MODE);
Packit 1fb8d4
	return server;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void shadow_server_free(rdpShadowServer* server)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!server)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	free(server->ipcSocket);
Packit 1fb8d4
	server->ipcSocket = NULL;
Packit 1fb8d4
	freerdp_settings_free(server->settings);
Packit 1fb8d4
	server->settings = NULL;
Packit 1fb8d4
	free(server);
Packit 1fb8d4
}
Packit 1fb8d4