Blame client/common/client.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 * FreeRDP Client Common
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <string.h>
Packit Service fa4841
#include <errno.h>
Packit Service fa4841
Packit Service fa4841
#include <freerdp/client.h>
Packit Service fa4841
Packit Service fa4841
#include <freerdp/addin.h>
Packit Service fa4841
#include <freerdp/assistance.h>
Packit Service fa4841
#include <freerdp/client/file.h>
Packit Service fa4841
#include <freerdp/utils/passphrase.h>
Packit Service fa4841
#include <freerdp/client/cmdline.h>
Packit Service fa4841
#include <freerdp/client/channels.h>
Packit Service fa4841
Packit Service fa4841
#include <freerdp/log.h>
Packit Service fa4841
#define TAG CLIENT_TAG("common")
Packit Service fa4841
Packit Service fa4841
static BOOL freerdp_client_common_new(freerdp* instance, rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
Packit Service fa4841
	return IFCALLRESULT(TRUE, pEntryPoints->ClientNew, instance, context);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void freerdp_client_common_free(freerdp* instance, rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
Packit Service fa4841
	IFCALL(pEntryPoints->ClientFree, instance, context);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/* Common API */
Packit Service fa4841
Packit Service fa4841
rdpContext* freerdp_client_context_new(RDP_CLIENT_ENTRY_POINTS* pEntryPoints)
Packit Service fa4841
{
Packit Service fa4841
	freerdp* instance;
Packit Service fa4841
	rdpContext* context;
Packit Service fa4841
Packit Service fa4841
	if (!pEntryPoints)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	IFCALL(pEntryPoints->GlobalInit);
Packit Service fa4841
	instance = freerdp_new();
Packit Service fa4841
Packit Service fa4841
	if (!instance)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	instance->settings = pEntryPoints->settings;
Packit Service fa4841
	instance->ContextSize = pEntryPoints->ContextSize;
Packit Service fa4841
	instance->ContextNew = freerdp_client_common_new;
Packit Service fa4841
	instance->ContextFree = freerdp_client_common_free;
Packit Service b1ea74
	instance->pClientEntryPoints = (RDP_CLIENT_ENTRY_POINTS*)malloc(pEntryPoints->Size);
Packit Service fa4841
Packit Service fa4841
	if (!instance->pClientEntryPoints)
Packit Service fa4841
		goto out_fail;
Packit Service fa4841
Packit Service fa4841
	CopyMemory(instance->pClientEntryPoints, pEntryPoints, pEntryPoints->Size);
Packit Service fa4841
Packit Service fa4841
	if (!freerdp_context_new(instance))
Packit Service fa4841
		goto out_fail2;
Packit Service fa4841
Packit Service fa4841
	context = instance->context;
Packit Service fa4841
	context->instance = instance;
Packit Service fa4841
	context->settings = instance->settings;
Packit Service fa4841
Packit Service b1ea74
	if (freerdp_register_addin_provider(freerdp_channels_load_static_addin_entry, 0) !=
Packit Service b1ea74
	    CHANNEL_RC_OK)
Packit Service fa4841
		goto out_fail2;
Packit Service fa4841
Packit Service fa4841
	return context;
Packit Service fa4841
out_fail2:
Packit Service fa4841
	free(instance->pClientEntryPoints);
Packit Service fa4841
out_fail:
Packit Service fa4841
	freerdp_free(instance);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void freerdp_client_context_free(rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	freerdp* instance;
Packit Service fa4841
Packit Service fa4841
	if (!context)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	instance = context->instance;
Packit Service fa4841
Packit Service fa4841
	if (instance)
Packit Service fa4841
	{
Packit Service fa4841
		RDP_CLIENT_ENTRY_POINTS* pEntryPoints = instance->pClientEntryPoints;
Packit Service fa4841
		freerdp_context_free(instance);
Packit Service fa4841
Packit Service fa4841
		if (pEntryPoints)
Packit Service fa4841
			IFCALL(pEntryPoints->GlobalUninit);
Packit Service fa4841
Packit Service fa4841
		free(instance->pClientEntryPoints);
Packit Service fa4841
		freerdp_free(instance);
Packit Service fa4841
	}
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
int freerdp_client_start(rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	RDP_CLIENT_ENTRY_POINTS* pEntryPoints;
Packit Service fa4841
Packit Service fa4841
	if (!context || !context->instance || !context->instance->pClientEntryPoints)
Packit Service fa4841
		return ERROR_BAD_ARGUMENTS;
Packit Service fa4841
Packit Service fa4841
	pEntryPoints = context->instance->pClientEntryPoints;
Packit Service fa4841
	return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStart, context);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
int freerdp_client_stop(rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	RDP_CLIENT_ENTRY_POINTS* pEntryPoints;
Packit Service fa4841
Packit Service fa4841
	if (!context || !context->instance || !context->instance->pClientEntryPoints)
Packit Service fa4841
		return ERROR_BAD_ARGUMENTS;
Packit Service fa4841
Packit Service fa4841
	pEntryPoints = context->instance->pClientEntryPoints;
Packit Service fa4841
	return IFCALLRESULT(CHANNEL_RC_OK, pEntryPoints->ClientStop, context);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
freerdp* freerdp_client_get_instance(rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	if (!context || !context->instance)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	return context->instance;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
HANDLE freerdp_client_get_thread(rdpContext* context)
Packit Service fa4841
{
Packit Service fa4841
	if (!context)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service b1ea74
	return ((rdpClientContext*)context)->thread;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL freerdp_client_settings_post_process(rdpSettings* settings)
Packit Service fa4841
{
Packit Service fa4841
	/* Moved GatewayUseSameCredentials logic outside of cmdline.c, so
Packit Service fa4841
	 * that the rdp file also triggers this functionality */
Packit Service fa4841
	if (settings->GatewayEnabled)
Packit Service fa4841
	{
Packit Service fa4841
		if (settings->GatewayUseSameCredentials)
Packit Service fa4841
		{
Packit Service fa4841
			if (settings->Username)
Packit Service fa4841
			{
Packit Service fa4841
				free(settings->GatewayUsername);
Packit Service fa4841
				settings->GatewayUsername = _strdup(settings->Username);
Packit Service fa4841
Packit Service fa4841
				if (!settings->GatewayUsername)
Packit Service fa4841
					goto out_error;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			if (settings->Domain)
Packit Service fa4841
			{
Packit Service fa4841
				free(settings->GatewayDomain);
Packit Service fa4841
				settings->GatewayDomain = _strdup(settings->Domain);
Packit Service fa4841
Packit Service fa4841
				if (!settings->GatewayDomain)
Packit Service fa4841
					goto out_error;
Packit Service fa4841
			}
Packit Service fa4841
Packit Service fa4841
			if (settings->Password)
Packit Service fa4841
			{
Packit Service fa4841
				free(settings->GatewayPassword);
Packit Service fa4841
				settings->GatewayPassword = _strdup(settings->Password);
Packit Service fa4841
Packit Service fa4841
				if (!settings->GatewayPassword)
Packit Service fa4841
					goto out_error;
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* Moved logic for Multimon and Span monitors to force fullscreen, so
Packit Service fa4841
	 * that the rdp file also triggers this functionality */
Packit Service fa4841
	if (settings->SpanMonitors)
Packit Service fa4841
	{
Packit Service fa4841
		settings->UseMultimon = TRUE;
Packit Service fa4841
		settings->Fullscreen = TRUE;
Packit Service fa4841
	}
Packit Service fa4841
	else if (settings->UseMultimon)
Packit Service fa4841
	{
Packit Service fa4841
		settings->Fullscreen = TRUE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
out_error:
Packit Service fa4841
	free(settings->GatewayUsername);
Packit Service fa4841
	free(settings->GatewayDomain);
Packit Service fa4841
	free(settings->GatewayPassword);
Packit Service fa4841
	return FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
int freerdp_client_settings_parse_command_line(rdpSettings* settings, int argc, char** argv,
Packit Service b1ea74
                                               BOOL allowUnknown)
Packit Service fa4841
{
Packit Service fa4841
	int status;
Packit Service fa4841
Packit Service fa4841
	if (argc < 1)
Packit Service fa4841
		return 0;
Packit Service fa4841
Packit Service fa4841
	if (!argv)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service b1ea74
	status =
Packit Service b1ea74
	    freerdp_client_settings_parse_command_line_arguments(settings, argc, argv, allowUnknown);
Packit Service fa4841
Packit Service fa4841
	if (status < 0)
Packit Service fa4841
		return status;
Packit Service fa4841
Packit Service fa4841
	/* This function will call logic that is applicable to the settings
Packit Service fa4841
	 * from command line parsing AND the rdp file parsing */
Packit Service fa4841
	if (!freerdp_client_settings_post_process(settings))
Packit Service fa4841
		status = -1;
Packit Service fa4841
Packit Service b1ea74
	WLog_DBG(TAG, "This is %s", freerdp_get_build_config());
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
int freerdp_client_settings_parse_connection_file(rdpSettings* settings, const char* filename)
Packit Service fa4841
{
Packit Service fa4841
	rdpFile* file;
Packit Service fa4841
	int ret = -1;
Packit Service fa4841
	file = freerdp_client_rdp_file_new();
Packit Service fa4841
Packit Service fa4841
	if (!file)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	if (!freerdp_client_parse_rdp_file(file, filename))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!freerdp_client_populate_settings_from_rdp_file(file, settings))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	ret = 0;
Packit Service fa4841
out:
Packit Service fa4841
	freerdp_client_rdp_file_free(file);
Packit Service fa4841
	return ret;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
int freerdp_client_settings_parse_connection_file_buffer(rdpSettings* settings, const BYTE* buffer,
Packit Service b1ea74
                                                         size_t size)
Packit Service fa4841
{
Packit Service fa4841
	rdpFile* file;
Packit Service fa4841
	int status = -1;
Packit Service fa4841
	file = freerdp_client_rdp_file_new();
Packit Service fa4841
Packit Service fa4841
	if (!file)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service b1ea74
	if (freerdp_client_parse_rdp_file_buffer(file, buffer, size) &&
Packit Service b1ea74
	    freerdp_client_populate_settings_from_rdp_file(file, settings))
Packit Service fa4841
	{
Packit Service fa4841
		status = 0;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	freerdp_client_rdp_file_free(file);
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
int freerdp_client_settings_write_connection_file(const rdpSettings* settings, const char* filename,
Packit Service b1ea74
                                                  BOOL unicode)
Packit Service fa4841
{
Packit Service fa4841
	rdpFile* file;
Packit Service fa4841
	int ret = -1;
Packit Service fa4841
	file = freerdp_client_rdp_file_new();
Packit Service fa4841
Packit Service fa4841
	if (!file)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	if (!freerdp_client_populate_rdp_file_from_settings(file, settings))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	if (!freerdp_client_write_rdp_file(file, filename, unicode))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	ret = 0;
Packit Service fa4841
out:
Packit Service fa4841
	freerdp_client_rdp_file_free(file);
Packit Service fa4841
	return ret;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
int freerdp_client_settings_parse_assistance_file(rdpSettings* settings, int argc, char* argv[])
Packit Service fa4841
{
Packit Service b1ea74
	int status, x;
Packit Service fa4841
	int ret = -1;
Packit Service b1ea74
	char* filename;
Packit Service b1ea74
	char* password = NULL;
Packit Service fa4841
	rdpAssistanceFile* file;
Packit Service b1ea74
Packit Service b1ea74
	if (!settings || !argv || (argc < 2))
Packit Service b1ea74
		return -1;
Packit Service b1ea74
Packit Service b1ea74
	filename = argv[1];
Packit Service b1ea74
Packit Service b1ea74
	for (x = 2; x < argc; x++)
Packit Service b1ea74
	{
Packit Service b1ea74
		const char* key = strstr(argv[x], "assistance:");
Packit Service b1ea74
Packit Service b1ea74
		if (key)
Packit Service b1ea74
			password = strchr(key, ':') + 1;
Packit Service b1ea74
	}
Packit Service b1ea74
Packit Service fa4841
	file = freerdp_assistance_file_new();
Packit Service fa4841
Packit Service fa4841
	if (!file)
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service b1ea74
	status = freerdp_assistance_parse_file(file, filename, password);
Packit Service fa4841
Packit Service fa4841
	if (status < 0)
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service b1ea74
	if (!freerdp_assistance_populate_settings_from_assistance_file(file, settings))
Packit Service fa4841
		goto out;
Packit Service fa4841
Packit Service fa4841
	ret = 0;
Packit Service fa4841
out:
Packit Service fa4841
	freerdp_assistance_file_free(file);
Packit Service fa4841
	return ret;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/** Callback set in the rdp_freerdp structure, and used to get the user's password,
Packit Service fa4841
 *  if required to establish the connection.
Packit Service fa4841
 *  This function is actually called in credssp_ntlmssp_client_init()
Packit Service fa4841
 *  @see rdp_server_accept_nego() and rdp_check_fds()
Packit Service fa4841
 *  @param instance - pointer to the rdp_freerdp structure that contains the connection settings
Packit Service fa4841
 *  @param username - unused
Packit Service b1ea74
 *  @param password - on return: pointer to a character string that will be filled by the password
Packit Service b1ea74
 * entered by the user. Note that this character string will be allocated inside the function, and
Packit Service b1ea74
 * needs to be deallocated by the caller using free(), even in case this function fails.
Packit Service fa4841
 *  @param domain - unused
Packit Service b1ea74
 *  @return TRUE if a password was successfully entered. See freerdp_passphrase_read() for more
Packit Service b1ea74
 * details.
Packit Service fa4841
 */
Packit Service b1ea74
static BOOL client_cli_authenticate_raw(freerdp* instance, BOOL gateway, char** username,
Packit Service fa4841
                                        char** password, char** domain)
Packit Service fa4841
{
Packit Service fa4841
	static const size_t password_size = 512;
Packit Service b1ea74
	const char* auth[] = { "Username: ", "Domain:   ", "Password: " };
Packit Service b1ea74
	const char* gw[] = { "GatewayUsername: ", "GatewayDomain:   ", "GatewayPassword: " };
Packit Service fa4841
	const char** prompt = (gateway) ? gw : auth;
Packit Service fa4841
Packit Service fa4841
	if (!username || !password || !domain)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!*username)
Packit Service fa4841
	{
Packit Service fa4841
		size_t username_size = 0;
Packit Service fa4841
		printf("%s", prompt[0]);
Packit Service fa4841
Packit Service fa4841
		if (GetLine(username, &username_size, stdin) < 0)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "GetLine returned %s [%d]", strerror(errno), errno);
Packit Service fa4841
			goto fail;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (*username)
Packit Service fa4841
		{
Packit Service fa4841
			*username = StrSep(username, "\r");
Packit Service fa4841
			*username = StrSep(username, "\n");
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!*domain)
Packit Service fa4841
	{
Packit Service fa4841
		size_t domain_size = 0;
Packit Service fa4841
		printf("%s", prompt[1]);
Packit Service fa4841
Packit Service fa4841
		if (GetLine(domain, &domain_size, stdin) < 0)
Packit Service fa4841
		{
Packit Service fa4841
			WLog_ERR(TAG, "GetLine returned %s [%d]", strerror(errno), errno);
Packit Service fa4841
			goto fail;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (*domain)
Packit Service fa4841
		{
Packit Service fa4841
			*domain = StrSep(domain, "\r");
Packit Service fa4841
			*domain = StrSep(domain, "\n");
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	if (!*password)
Packit Service fa4841
	{
Packit Service fa4841
		*password = calloc(password_size, sizeof(char));
Packit Service fa4841
Packit Service fa4841
		if (!*password)
Packit Service fa4841
			goto fail;
Packit Service fa4841
Packit Service fa4841
		if (freerdp_passphrase_read(prompt[2], *password, password_size,
Packit Service fa4841
		                            instance->settings->CredentialsFromStdin) == NULL)
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
fail:
Packit Service fa4841
	free(*username);
Packit Service fa4841
	free(*domain);
Packit Service fa4841
	free(*password);
Packit Service fa4841
	*username = NULL;
Packit Service fa4841
	*domain = NULL;
Packit Service fa4841
	*password = NULL;
Packit Service fa4841
	return FALSE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
BOOL client_cli_authenticate(freerdp* instance, char** username, char** password, char** domain)
Packit Service fa4841
{
Packit Service fa4841
	if (instance->settings->SmartcardLogon)
Packit Service fa4841
	{
Packit Service fa4841
		WLog_INFO(TAG, "Authentication via smartcard");
Packit Service fa4841
		return TRUE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return client_cli_authenticate_raw(instance, FALSE, username, password, domain);
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
BOOL client_cli_gw_authenticate(freerdp* instance, char** username, char** password, char** domain)
Packit Service fa4841
{
Packit Service fa4841
	return client_cli_authenticate_raw(instance, TRUE, username, password, domain);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static DWORD client_cli_accept_certificate(rdpSettings* settings)
Packit Service fa4841
{
Packit Service fa4841
	char answer;
Packit Service fa4841
Packit Service fa4841
	if (settings->CredentialsFromStdin)
Packit Service fa4841
		return 0;
Packit Service fa4841
Packit Service fa4841
	while (1)
Packit Service fa4841
	{
Packit Service fa4841
		printf("Do you trust the above certificate? (Y/T/N) ");
Packit Service fa4841
		fflush(stdout);
Packit Service fa4841
		answer = fgetc(stdin);
Packit Service fa4841
Packit Service fa4841
		if (feof(stdin))
Packit Service fa4841
		{
Packit Service fa4841
			printf("\nError: Could not read answer from stdin.");
Packit Service fa4841
Packit Service fa4841
			if (settings->CredentialsFromStdin)
Packit Service fa4841
				printf(" - Run without parameter \"--from-stdin\" to set trust.");
Packit Service fa4841
Packit Service fa4841
			printf("\n");
Packit Service fa4841
			return 0;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		switch (answer)
Packit Service fa4841
		{
Packit Service fa4841
			case 'y':
Packit Service fa4841
			case 'Y':
Packit Service b1ea74
				fgetc(stdin);
Packit Service fa4841
				return 1;
Packit Service fa4841
Packit Service fa4841
			case 't':
Packit Service fa4841
			case 'T':
Packit Service b1ea74
				fgetc(stdin);
Packit Service fa4841
				return 2;
Packit Service fa4841
Packit Service fa4841
			case 'n':
Packit Service fa4841
			case 'N':
Packit Service b1ea74
				fgetc(stdin);
Packit Service fa4841
				return 0;
Packit Service fa4841
Packit Service fa4841
			default:
Packit Service fa4841
				break;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		printf("\n");
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return 0;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/** Callback set in the rdp_freerdp structure, and used to make a certificate validation
Packit Service fa4841
 *  when the connection requires it.
Packit Service fa4841
 *  This function will actually be called by tls_verify_certificate().
Packit Service fa4841
 *  @see rdp_client_connect() and tls_connect()
Packit Service b1ea74
 *  @deprecated Use client_cli_verify_certificate_ex
Packit Service fa4841
 *  @param instance - pointer to the rdp_freerdp structure that contains the connection settings
Packit Service fa4841
 *  @param common_name
Packit Service fa4841
 *  @param subject
Packit Service fa4841
 *  @param issuer
Packit Service fa4841
 *  @param fingerprint
Packit Service fa4841
 *  @param host_mismatch Indicates the certificate host does not match.
Packit Service fa4841
 *  @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise.
Packit Service fa4841
 */
Packit Service b1ea74
DWORD client_cli_verify_certificate(freerdp* instance, const char* common_name, const char* subject,
Packit Service b1ea74
                                    const char* issuer, const char* fingerprint, BOOL host_mismatch)
Packit Service fa4841
{
Packit Service b1ea74
	WINPR_UNUSED(common_name);
Packit Service b1ea74
	WINPR_UNUSED(host_mismatch);
Packit Service b1ea74
Packit Service b1ea74
	printf("WARNING: This callback is deprecated, migrate to client_cli_verify_certificate_ex\n");
Packit Service fa4841
	printf("Certificate details:\n");
Packit Service fa4841
	printf("\tSubject: %s\n", subject);
Packit Service fa4841
	printf("\tIssuer: %s\n", issuer);
Packit Service fa4841
	printf("\tThumbprint: %s\n", fingerprint);
Packit Service fa4841
	printf("The above X.509 certificate could not be verified, possibly because you do not have\n"
Packit Service fa4841
	       "the CA certificate in your certificate store, or the certificate has expired.\n"
Packit Service fa4841
	       "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
Packit Service fa4841
	return client_cli_accept_certificate(instance->settings);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/** Callback set in the rdp_freerdp structure, and used to make a certificate validation
Packit Service b1ea74
 *  when the connection requires it.
Packit Service b1ea74
 *  This function will actually be called by tls_verify_certificate().
Packit Service b1ea74
 *  @see rdp_client_connect() and tls_connect()
Packit Service b1ea74
 *  @param instance     pointer to the rdp_freerdp structure that contains the connection settings
Packit Service b1ea74
 *  @param host         The host currently connecting to
Packit Service b1ea74
 *  @param port         The port currently connecting to
Packit Service b1ea74
 *  @param common_name  The common name of the certificate, should match host or an alias of it
Packit Service b1ea74
 *  @param subject      The subject of the certificate
Packit Service b1ea74
 *  @param issuer       The certificate issuer name
Packit Service b1ea74
 *  @param fingerprint  The fingerprint of the certificate
Packit Service b1ea74
 *  @param flags        See VERIFY_CERT_FLAG_* for possible values.
Packit Service b1ea74
 *
Packit Service b1ea74
 *  @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise.
Packit Service b1ea74
 */
Packit Service b1ea74
DWORD client_cli_verify_certificate_ex(freerdp* instance, const char* host, UINT16 port,
Packit Service b1ea74
                                       const char* common_name, const char* subject,
Packit Service b1ea74
                                       const char* issuer, const char* fingerprint, DWORD flags)
Packit Service b1ea74
{
Packit Service b1ea74
	const char* type = "RDP-Server";
Packit Service b1ea74
Packit Service b1ea74
	if (flags & VERIFY_CERT_FLAG_GATEWAY)
Packit Service b1ea74
		type = "RDP-Gateway";
Packit Service b1ea74
Packit Service b1ea74
	if (flags & VERIFY_CERT_FLAG_REDIRECT)
Packit Service b1ea74
		type = "RDP-Redirect";
Packit Service b1ea74
Packit Service b1ea74
	printf("Certificate details for %s:%" PRIu16 " (%s):\n", host, port, type);
Packit Service b1ea74
	printf("\tCommon Name: %s\n", common_name);
Packit Service b1ea74
	printf("\tSubject:     %s\n", subject);
Packit Service b1ea74
	printf("\tIssuer:      %s\n", issuer);
Packit Service b1ea74
	printf("\tThumbprint:  %s\n", fingerprint);
Packit Service b1ea74
Packit Service b1ea74
	printf("The above X.509 certificate could not be verified, possibly because you do not have\n"
Packit Service b1ea74
	       "the CA certificate in your certificate store, or the certificate has expired.\n"
Packit Service b1ea74
	       "Please look at the OpenSSL documentation on how to add a private CA to the store.\n");
Packit Service b1ea74
	return client_cli_accept_certificate(instance->settings);
Packit Service b1ea74
}
Packit Service b1ea74
Packit Service b1ea74
/** Callback set in the rdp_freerdp structure, and used to make a certificate validation
Packit Service fa4841
 *  when a stored certificate does not match the remote counterpart.
Packit Service fa4841
 *  This function will actually be called by tls_verify_certificate().
Packit Service fa4841
 *  @see rdp_client_connect() and tls_connect()
Packit Service b1ea74
 *  @deprecated Use client_cli_verify_changed_certificate_ex
Packit Service fa4841
 *  @param instance - pointer to the rdp_freerdp structure that contains the connection settings
Packit Service fa4841
 *  @param common_name
Packit Service fa4841
 *  @param subject
Packit Service fa4841
 *  @param issuer
Packit Service fa4841
 *  @param fingerprint
Packit Service fa4841
 *  @param old_subject
Packit Service fa4841
 *  @param old_issuer
Packit Service fa4841
 *  @param old_fingerprint
Packit Service fa4841
 *  @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise.
Packit Service fa4841
 */
Packit Service b1ea74
DWORD client_cli_verify_changed_certificate(freerdp* instance, const char* common_name,
Packit Service b1ea74
                                            const char* subject, const char* issuer,
Packit Service b1ea74
                                            const char* fingerprint, const char* old_subject,
Packit Service b1ea74
                                            const char* old_issuer, const char* old_fingerprint)
Packit Service fa4841
{
Packit Service b1ea74
	WINPR_UNUSED(common_name);
Packit Service b1ea74
Packit Service b1ea74
	printf("WARNING: This callback is deprecated, migrate to "
Packit Service b1ea74
	       "client_cli_verify_changed_certificate_ex\n");
Packit Service fa4841
	printf("!!! Certificate has changed !!!\n");
Packit Service fa4841
	printf("\n");
Packit Service fa4841
	printf("New Certificate details:\n");
Packit Service fa4841
	printf("\tSubject: %s\n", subject);
Packit Service fa4841
	printf("\tIssuer: %s\n", issuer);
Packit Service fa4841
	printf("\tThumbprint: %s\n", fingerprint);
Packit Service fa4841
	printf("\n");
Packit Service fa4841
	printf("Old Certificate details:\n");
Packit Service fa4841
	printf("\tSubject: %s\n", old_subject);
Packit Service fa4841
	printf("\tIssuer: %s\n", old_issuer);
Packit Service fa4841
	printf("\tThumbprint: %s\n", old_fingerprint);
Packit Service fa4841
	printf("\n");
Packit Service b1ea74
	printf("The above X.509 certificate does not match the certificate used for previous "
Packit Service b1ea74
	       "connections.\n"
Packit Service b1ea74
	       "This may indicate that the certificate has been tampered with.\n"
Packit Service b1ea74
	       "Please contact the administrator of the RDP server and clarify.\n");
Packit Service b1ea74
	return client_cli_accept_certificate(instance->settings);
Packit Service b1ea74
}
Packit Service b1ea74
Packit Service b1ea74
/** Callback set in the rdp_freerdp structure, and used to make a certificate validation
Packit Service b1ea74
 *  when a stored certificate does not match the remote counterpart.
Packit Service b1ea74
 *  This function will actually be called by tls_verify_certificate().
Packit Service b1ea74
 *  @see rdp_client_connect() and tls_connect()
Packit Service b1ea74
 *  @param instance        pointer to the rdp_freerdp structure that contains the connection
Packit Service b1ea74
 * settings
Packit Service b1ea74
 *  @param host            The host currently connecting to
Packit Service b1ea74
 *  @param port            The port currently connecting to
Packit Service b1ea74
 *  @param common_name     The common name of the certificate, should match host or an alias of it
Packit Service b1ea74
 *  @param subject         The subject of the certificate
Packit Service b1ea74
 *  @param issuer          The certificate issuer name
Packit Service b1ea74
 *  @param fingerprint     The fingerprint of the certificate
Packit Service b1ea74
 *  @param old_subject     The subject of the previous certificate
Packit Service b1ea74
 *  @param old_issuer      The previous certificate issuer name
Packit Service b1ea74
 *  @param old_fingerprint The fingerprint of the previous certificate
Packit Service b1ea74
 *  @param flags           See VERIFY_CERT_FLAG_* for possible values.
Packit Service b1ea74
 *
Packit Service b1ea74
 *  @return 1 if the certificate is trusted, 2 if temporary trusted, 0 otherwise.
Packit Service b1ea74
 */
Packit Service b1ea74
DWORD client_cli_verify_changed_certificate_ex(freerdp* instance, const char* host, UINT16 port,
Packit Service b1ea74
                                               const char* common_name, const char* subject,
Packit Service b1ea74
                                               const char* issuer, const char* fingerprint,
Packit Service b1ea74
                                               const char* old_subject, const char* old_issuer,
Packit Service b1ea74
                                               const char* old_fingerprint, DWORD flags)
Packit Service b1ea74
{
Packit Service b1ea74
	const char* type = "RDP-Server";
Packit Service b1ea74
Packit Service b1ea74
	if (flags & VERIFY_CERT_FLAG_GATEWAY)
Packit Service b1ea74
		type = "RDP-Gateway";
Packit Service b1ea74
Packit Service b1ea74
	if (flags & VERIFY_CERT_FLAG_REDIRECT)
Packit Service b1ea74
		type = "RDP-Redirect";
Packit Service b1ea74
Packit Service b1ea74
	printf("!!!Certificate for %s:%" PRIu16 " (%s) has changed!!!\n", host, port, type);
Packit Service b1ea74
	printf("\n");
Packit Service b1ea74
	printf("New Certificate details:\n");
Packit Service b1ea74
	printf("\tCommon Name: %s\n", common_name);
Packit Service b1ea74
	printf("\tSubject:     %s\n", subject);
Packit Service b1ea74
	printf("\tIssuer:      %s\n", issuer);
Packit Service b1ea74
	printf("\tThumbprint:  %s\n", fingerprint);
Packit Service b1ea74
	printf("\n");
Packit Service b1ea74
	printf("Old Certificate details:\n");
Packit Service b1ea74
	printf("\tSubject:     %s\n", old_subject);
Packit Service b1ea74
	printf("\tIssuer:      %s\n", old_issuer);
Packit Service b1ea74
	printf("\tThumbprint:  %s\n", old_fingerprint);
Packit Service b1ea74
	printf("\n");
Packit Service b1ea74
	if (flags & VERIFY_CERT_FLAG_MATCH_LEGACY_SHA1)
Packit Service b1ea74
	{
Packit Service b1ea74
		printf("\tA matching entry with legacy SHA1 was found in local known_hosts2 store.\n");
Packit Service b1ea74
		printf("\tIf you just upgraded from a FreeRDP version before 2.0 this is expected.\n");
Packit Service b1ea74
		printf("\tThe hashing algorithm has been upgraded from SHA1 to SHA256.\n");
Packit Service b1ea74
		printf("\tAll manually accepted certificates must be reconfirmed!\n");
Packit Service b1ea74
		printf("\n");
Packit Service b1ea74
	}
Packit Service b1ea74
	printf("The above X.509 certificate does not match the certificate used for previous "
Packit Service b1ea74
	       "connections.\n"
Packit Service fa4841
	       "This may indicate that the certificate has been tampered with.\n"
Packit Service fa4841
	       "Please contact the administrator of the RDP server and clarify.\n");
Packit Service fa4841
	return client_cli_accept_certificate(instance->settings);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL client_auto_reconnect(freerdp* instance)
Packit Service fa4841
{
Packit Service fa4841
	return client_auto_reconnect_ex(instance, NULL);
Packit Service fa4841
}
Packit Service fa4841
Packit Service b1ea74
BOOL client_auto_reconnect_ex(freerdp* instance, BOOL (*window_events)(freerdp* instance))
Packit Service fa4841
{
Packit Service fa4841
	UINT32 maxRetries;
Packit Service fa4841
	UINT32 numRetries = 0;
Packit Service fa4841
	rdpSettings* settings;
Packit Service fa4841
Packit Service fa4841
	if (!instance || !instance->settings)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	settings = instance->settings;
Packit Service fa4841
	maxRetries = settings->AutoReconnectMaxRetries;
Packit Service fa4841
Packit Service fa4841
	/* Only auto reconnect on network disconnects. */
Packit Service fa4841
	if (freerdp_error_info(instance) != 0)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	/* A network disconnect was detected */
Packit Service fa4841
	WLog_INFO(TAG, "Network disconnect!");
Packit Service fa4841
Packit Service fa4841
	if (!settings->AutoReconnectionEnabled)
Packit Service fa4841
	{
Packit Service fa4841
		/* No auto-reconnect - just quit */
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* Perform an auto-reconnect. */
Packit Service fa4841
	while (TRUE)
Packit Service fa4841
	{
Packit Service fa4841
		UINT32 x;
Packit Service fa4841
Packit Service fa4841
		/* Quit retrying if max retries has been exceeded */
Packit Service fa4841
		if ((maxRetries > 0) && (numRetries++ >= maxRetries))
Packit Service fa4841
		{
Packit Service fa4841
			return FALSE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		/* Attempt the next reconnect */
Packit Service b1ea74
		WLog_INFO(TAG, "Attempting reconnect (%" PRIu32 " of %" PRIu32 ")", numRetries, maxRetries);
Packit Service fa4841
Packit Service fa4841
		if (freerdp_reconnect(instance))
Packit Service fa4841
			return TRUE;
Packit Service fa4841
Packit Service fa4841
		for (x = 0; x < 50; x++)
Packit Service fa4841
		{
Packit Service fa4841
			if (!IFCALLRESULT(TRUE, window_events, instance))
Packit Service fa4841
				return FALSE;
Packit Service fa4841
Packit Service fa4841
			Sleep(100);
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	WLog_ERR(TAG, "Maximum reconnect retries exceeded");
Packit Service fa4841
	return FALSE;
Packit Service fa4841
}