Blame server/proxy/pf_capture.c

Packit Service 5a9772
/**
Packit Service 5a9772
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service 5a9772
 * FreeRDP Proxy Server Session Capture
Packit Service 5a9772
 *
Packit Service 5a9772
 * Copyright 2019 Kobi Mizrachi <kmizrachi18@gmail.com>
Packit Service 5a9772
 *
Packit Service 5a9772
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service 5a9772
 * you may not use this file except in compliance with the License.
Packit Service 5a9772
 * You may obtain a copy of the License at
Packit Service 5a9772
 *
Packit Service 5a9772
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service 5a9772
 *
Packit Service 5a9772
 * Unless required by applicable law or agreed to in writing, software
Packit Service 5a9772
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service 5a9772
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service 5a9772
 * See the License for the specific language governing permissions and
Packit Service 5a9772
 * limitations under the License.
Packit Service 5a9772
 */
Packit Service 5a9772
Packit Service 5a9772
#include <stdio.h>
Packit Service 5a9772
#include <string.h>
Packit Service 5a9772
#include <winpr/image.h>
Packit Service 5a9772
#include <winpr/sysinfo.h>
Packit Service 5a9772
#include <winpr/path.h>
Packit Service 5a9772
#include <winpr/file.h>
Packit Service 5a9772
Packit Service 5a9772
#include "pf_capture.h"
Packit Service 5a9772
Packit Service 5a9772
static BOOL pf_capture_create_dir_if_not_exists(const char* path)
Packit Service 5a9772
{
Packit Service 5a9772
	if (PathFileExistsA(path))
Packit Service 5a9772
		return TRUE;
Packit Service 5a9772
Packit Service 5a9772
	return CreateDirectoryA(path, NULL);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL pf_capture_create_user_captures_dir(const char* base_dir, const char* username)
Packit Service 5a9772
{
Packit Service 5a9772
	int rc;
Packit Service 5a9772
	size_t size;
Packit Service 5a9772
	char* buf = NULL;
Packit Service 5a9772
	BOOL ret = FALSE;
Packit Service 5a9772
Packit Service 5a9772
	/* create sub-directory in base captures directory for current username, if it doesn't already
Packit Service 5a9772
	 * exists. */
Packit Service 5a9772
	rc = _snprintf(NULL, 0, "%s/%s", base_dir, username);
Packit Service 5a9772
	if (rc < 0)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	size = (size_t)rc;
Packit Service 5a9772
Packit Service 5a9772
	buf = malloc(size + 1);
Packit Service 5a9772
	if (!buf)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	rc = sprintf(buf, "%s/%s", base_dir, username);
Packit Service 5a9772
	if (rc < 0 || (size_t)rc != size)
Packit Service 5a9772
		goto out;
Packit Service 5a9772
Packit Service 5a9772
	if (!pf_capture_create_dir_if_not_exists(buf))
Packit Service 5a9772
		goto out;
Packit Service 5a9772
Packit Service 5a9772
	ret = TRUE;
Packit Service 5a9772
Packit Service 5a9772
out:
Packit Service 5a9772
	free(buf);
Packit Service 5a9772
	return ret;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL pf_capture_create_current_session_captures_dir(pClientContext* pc)
Packit Service 5a9772
{
Packit Service 5a9772
	proxyConfig* config = pc->pdata->config;
Packit Service 5a9772
	rdpSettings* settings = pc->context.settings;
Packit Service 5a9772
	const char* fmt = "%s/%s/%s_%02u-%02u-%" PRIu16 "_%02u-%02u-%02u-%03u";
Packit Service 5a9772
	int rc;
Packit Service 5a9772
	size_t size;
Packit Service 5a9772
	SYSTEMTIME localTime;
Packit Service 5a9772
Packit Service 5a9772
	GetLocalTime(&localTime);
Packit Service 5a9772
Packit Service 5a9772
	/* create sub-directory in current user's captures directory, for the specific session. */
Packit Service 5a9772
	rc = _snprintf(NULL, 0, fmt, config->CapturesDirectory, settings->Username,
Packit Service 5a9772
	               settings->ServerHostname, localTime.wDay, localTime.wMonth, localTime.wYear,
Packit Service 5a9772
	               localTime.wHour, localTime.wMinute, localTime.wSecond, localTime.wMilliseconds);
Packit Service 5a9772
Packit Service 5a9772
	if (rc < 0)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	size = (size_t)rc;
Packit Service 5a9772
Packit Service 5a9772
	/* `pc->frames_dir` will be used by proxy client for saving frames to storage. */
Packit Service 5a9772
	pc->frames_dir = malloc(size + 1);
Packit Service 5a9772
	if (!pc->frames_dir)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	rc = sprintf(pc->frames_dir, fmt, config->CapturesDirectory, settings->Username,
Packit Service 5a9772
	             settings->ServerHostname, localTime.wDay, localTime.wMonth, localTime.wYear,
Packit Service 5a9772
	             localTime.wHour, localTime.wMinute, localTime.wSecond, localTime.wMilliseconds);
Packit Service 5a9772
Packit Service 5a9772
	if (rc < 0 || (size_t)rc != size)
Packit Service 5a9772
		goto error;
Packit Service 5a9772
Packit Service 5a9772
	if (!pf_capture_create_dir_if_not_exists(pc->frames_dir))
Packit Service 5a9772
		goto error;
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
Packit Service 5a9772
error:
Packit Service 5a9772
	free(pc->frames_dir);
Packit Service 5a9772
	return FALSE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/* creates a directory to store captured session frames.
Packit Service 5a9772
 *
Packit Service 5a9772
 * @context: current session.
Packit Service 5a9772
 *
Packit Service 5a9772
 * directory path will be: base_dir/username/session-start-date.
Packit Service 5a9772
 *
Packit Service 5a9772
 * it is important to call this function only after the connection is fully established, as it uses
Packit Service 5a9772
 * settings->Username and settings->ServerHostname values to create the directory. After the
Packit Service 5a9772
 * connection established, we know that those values are valid.
Packit Service 5a9772
 */
Packit Service 5a9772
BOOL pf_capture_create_session_directory(pClientContext* pc)
Packit Service 5a9772
{
Packit Service 5a9772
	proxyConfig* config = pc->pdata->config;
Packit Service 5a9772
	rdpSettings* settings = pc->context.settings;
Packit Service 5a9772
Packit Service 5a9772
	if (!pf_capture_create_user_captures_dir(config->CapturesDirectory, settings->Username))
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	if (!pf_capture_create_current_session_captures_dir(pc))
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
/* saves a captured frame in a BMP format. */
Packit Service 5a9772
BOOL pf_capture_save_frame(pClientContext* pc, const BYTE* frame)
Packit Service 5a9772
{
Packit Service 5a9772
	rdpSettings* settings = pc->context.settings;
Packit Service 5a9772
	int rc;
Packit Service 5a9772
	const char* fmt = "%s/%" PRIu64 ".bmp";
Packit Service 5a9772
	char* file_path = NULL;
Packit Service 5a9772
	size_t size;
Packit Service 5a9772
Packit Service 5a9772
	if (!pc->frames_dir)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	rc = _snprintf(NULL, 0, fmt, pc->frames_dir, pc->frames_count++);
Packit Service 5a9772
	if (rc < 0)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	size = (size_t)rc;
Packit Service 5a9772
	file_path = malloc(size + 1);
Packit Service 5a9772
	if (!file_path)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	rc = sprintf(file_path, fmt, pc->frames_dir, pc->frames_count++);
Packit Service 5a9772
	if (rc < 0 || (size_t)rc != size)
Packit Service 5a9772
		goto out;
Packit Service 5a9772
Packit Service 5a9772
	rc = winpr_bitmap_write(file_path, frame, settings->DesktopWidth, settings->DesktopHeight,
Packit Service 5a9772
	                        settings->ColorDepth);
Packit Service 5a9772
Packit Service 5a9772
out:
Packit Service 5a9772
	free(file_path);
Packit Service 5a9772
	return rc;
Packit Service 5a9772
}