Commit message: Fixed oob read in irp_write and similar
CVE: CVE-2020-11089
CWE: CWE-125
Vulnerability description: In FreeRDP before 2.1.0, there is an out-of-bound read in irp functions (parallel_process_irp_create, serial_process_irp_create, drive_process_irp_write, printer_process_irp_write, rdpei_recv_pdu, serial_process_irp_write). This has been fixed in 2.1.0.

Project: FreeRDP

static UINT rdpei_plugin_initialize(IWTSPlugin* pPlugin, IWTSVirtualChannelManager* pChannelMgr)
{
	UINT error;
	RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)pPlugin;
	rdpei->listener_callback = (RDPEI_LISTENER_CALLBACK*)calloc(1, sizeof(RDPEI_LISTENER_CALLBACK));

	if (!rdpei->listener_callback)
	{
		WLog_ERR(TAG, "calloc failed!");
		return CHANNEL_RC_NO_MEMORY;
	}

	rdpei->listener_callback->iface.OnNewChannelConnection = rdpei_on_new_channel_connection;
	rdpei->listener_callback->plugin = pPlugin;
	rdpei->listener_callback->channel_mgr = pChannelMgr;

	if ((error = pChannelMgr->CreateListener(pChannelMgr, RDPEI_DVC_CHANNEL_NAME, 0,
	                                         (IWTSListenerCallback*)rdpei->listener_callback,
	                                         &(rdpei->listener))))
	{
		WLog_ERR(TAG, "ChannelMgr->CreateListener failed with error %" PRIu32 "!", error);
		goto error_out;
	}

	rdpei->listener->pInterface = rdpei->iface.pInterface;

	return error;
error_out:
	free(rdpei->listener_callback);
	return error;
}

Project: FreeRDP

static void nego_attempt_nla(rdpNego* nego)
{
	nego->RequestedProtocols = PROTOCOL_HYBRID | PROTOCOL_SSL;
	WLog_DBG(TAG, "Attempting NLA security");

	if (!nego_transport_connect(nego))
	{
		nego->state = NEGO_STATE_FAIL;
		return;
	}

	if (!nego_send_negotiation_request(nego))
	{
		nego->state = NEGO_STATE_FAIL;
		return;
	}

	if (!nego_recv_response(nego))
	{
		nego->state = NEGO_STATE_FAIL;
		return;
	}

	WLog_DBG(TAG, "state: %s", nego_state_string(nego->state));

	if (nego->state != NEGO_STATE_FINAL)
	{
		nego_transport_disconnect(nego);

		if (nego->EnabledProtocols[PROTOCOL_SSL])
			nego->state = NEGO_STATE_TLS;
		else if (nego->EnabledProtocols[PROTOCOL_RDP])
			nego->state = NEGO_STATE_RDP;
		else
			nego->state = NEGO_STATE_FAIL;
	}
}

Project: FreeRDP

static BOOL printer_remove_config(const rdpSettings* settings, const WCHAR* name, size_t length)
{
	BOOL rc = FALSE;
	char* path = get_printer_config_path(settings, name, length);

	if (!printer_config_valid(path))
		goto fail;

	rc = RemoveDirectoryA(path);
fail:
	free(path);
	return rc;
}

Project: FreeRDP

static UINT printer_process_irp_device_control(PRINTER_DEVICE* printer_dev, IRP* irp)
{
	Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
	return irp->Complete(irp);
}

Project: FreeRDP

BOOL nego_set_requested_protocols(rdpNego* nego, UINT32 RequestedProtocols)
{
	if (!nego)
		return FALSE;

	nego->RequestedProtocols = RequestedProtocols;
	return TRUE;
}

Project: FreeRDP

void nego_set_negotiation_enabled(rdpNego* nego, BOOL NegotiateSecurityLayer)
{
	WLog_DBG(TAG, "Enabling security layer negotiation: %s",
	         NegotiateSecurityLayer ? "TRUE" : "FALSE");
	nego->NegotiateSecurityLayer = NegotiateSecurityLayer;
}

Project: FreeRDP

UINT rdpei_send_frame(RdpeiClientContext* context)
{
	UINT64 currentTime;
	RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle;
	RDPEI_CHANNEL_CALLBACK* callback = rdpei->listener_callback->channel_callback;
	UINT error;
	currentTime = GetTickCount64();

	if (!rdpei->previousFrameTime && !rdpei->currentFrameTime)
	{
		rdpei->currentFrameTime = currentTime;
		rdpei->frame.frameOffset = 0;
	}
	else
	{
		rdpei->currentFrameTime = currentTime;
		rdpei->frame.frameOffset = rdpei->currentFrameTime - rdpei->previousFrameTime;
	}

	if ((error = rdpei_send_touch_event_pdu(callback, &rdpei->frame)))
	{
		WLog_ERR(TAG, "rdpei_send_touch_event_pdu failed with error %" PRIu32 "!", error);
		return error;
	}

	rdpei->previousFrameTime = rdpei->currentFrameTime;
	rdpei->frame.contactCount = 0;
	return error;
}

Project: FreeRDP

static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp)
{
	UINT32 FileId;
	DRIVE_FILE* file;
	BYTE Information;
	UINT32 FileAttributes;
	UINT32 SharedAccess;
	UINT32 DesiredAccess;
	UINT32 CreateDisposition;
	UINT32 CreateOptions;
	UINT32 PathLength;
	UINT64 allocationSize;
	const WCHAR* path;

	if (!drive || !irp || !irp->devman || !irp->Complete)
		return ERROR_INVALID_PARAMETER;

	if (Stream_GetRemainingLength(irp->input) < 6 * 4 + 8)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, DesiredAccess);
	Stream_Read_UINT64(irp->input, allocationSize);
	Stream_Read_UINT32(irp->input, FileAttributes);
	Stream_Read_UINT32(irp->input, SharedAccess);
	Stream_Read_UINT32(irp->input, CreateDisposition);
	Stream_Read_UINT32(irp->input, CreateOptions);
	Stream_Read_UINT32(irp->input, PathLength);

	if (Stream_GetRemainingLength(irp->input) < PathLength)
		return ERROR_INVALID_DATA;

	path = (const WCHAR*)Stream_Pointer(irp->input);
	FileId = irp->devman->id_sequence++;
	file = drive_file_new(drive->path, path, PathLength, FileId, DesiredAccess, CreateDisposition,
	                      CreateOptions, FileAttributes, SharedAccess);

	if (!file)
	{
		irp->IoStatus = drive_map_windows_err(GetLastError());
		FileId = 0;
		Information = 0;
	}
	else
	{
		void* key = (void*)(size_t)file->id;

		if (!ListDictionary_Add(drive->files, key, file))
		{
			WLog_ERR(TAG, "ListDictionary_Add failed!");
			return ERROR_INTERNAL_ERROR;
		}

		switch (CreateDisposition)
		{
			case FILE_SUPERSEDE:
			case FILE_OPEN:
			case FILE_CREATE:
			case FILE_OVERWRITE:
				Information = FILE_SUPERSEDED;
				break;

			case FILE_OPEN_IF:
				Information = FILE_OPENED;
				break;

			case FILE_OVERWRITE_IF:
				Information = FILE_OVERWRITTEN;
				break;

			default:
				Information = 0;
				break;
		}
	}

	Stream_Write_UINT32(irp->output, FileId);
	Stream_Write_UINT8(irp->output, Information);
	return irp->Complete(irp);
}

Project: FreeRDP

BOOL nego_set_routing_token(rdpNego* nego, BYTE* RoutingToken, DWORD RoutingTokenLength)
{
	if (RoutingTokenLength == 0)
		return FALSE;

	free(nego->RoutingToken);
	nego->RoutingTokenLength = RoutingTokenLength;
	nego->RoutingToken = (BYTE*)malloc(nego->RoutingTokenLength);

	if (!nego->RoutingToken)
		return FALSE;

	CopyMemory(nego->RoutingToken, RoutingToken, nego->RoutingTokenLength);
	return TRUE;
}

Project: FreeRDP

static UINT rdpei_on_data_received(IWTSVirtualChannelCallback* pChannelCallback, wStream* data)
{
	RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*)pChannelCallback;
	return rdpei_recv_pdu(callback, data);
}

Project: FreeRDP

static void drive_file_objfree(void* obj)
{
	drive_file_free((DRIVE_FILE*)obj);
}

Project: FreeRDP

static char* get_printer_config_path(const rdpSettings* settings, const WCHAR* name, size_t length)
{
	char* dir = GetCombinedPath(settings->ConfigPath, "printers");
	char* bname = crypto_base64_encode((const BYTE*)name, (int)length);
	char* config = GetCombinedPath(dir, bname);

	if (config && !PathFileExistsA(config))
	{
		if (!PathMakePathA(config, NULL))
		{
			free(config);
			config = NULL;
		}
	}

	free(dir);
	free(bname);
	return config;
}

Project: FreeRDP

static BOOL printer_move_config(const rdpSettings* settings, const WCHAR* oldName, size_t oldLength,
                                const WCHAR* newName, size_t newLength)
{
	BOOL rc = FALSE;
	char* oldPath = get_printer_config_path(settings, oldName, oldLength);
	char* newPath = get_printer_config_path(settings, newName, newLength);

	if (printer_config_valid(oldPath))
		rc = MoveFileA(oldPath, newPath);

	free(oldPath);
	free(newPath);
	return rc;
}

Project: FreeRDP

rdpNego* nego_new(rdpTransport* transport)
{
	rdpNego* nego = (rdpNego*)calloc(1, sizeof(rdpNego));

	if (!nego)
		return NULL;

	nego->transport = transport;
	nego_init(nego);
	return nego;
}

Project: FreeRDP

static DWORD WINAPI irp_thread_func(LPVOID arg)
{
	IRP_THREAD_DATA* data = (IRP_THREAD_DATA*)arg;
	UINT error;

	/* blocks until the end of the request */
	if ((error = serial_process_irp(data->serial, data->irp)))
	{
		WLog_ERR(TAG, "serial_process_irp failed with error %" PRIu32 "", error);
		goto error_out;
	}

	EnterCriticalSection(&data->serial->TerminatingIrpThreadsLock);
	data->serial->IrpThreadToBeTerminatedCount++;
	error = data->irp->Complete(data->irp);
	LeaveCriticalSection(&data->serial->TerminatingIrpThreadsLock);
error_out:

	if (error && data->serial->rdpcontext)
		setChannelError(data->serial->rdpcontext, error, "irp_thread_func reported an error");

	/* NB: At this point, the server might already being reusing
	 * the CompletionId whereas the thread is not yet
	 * terminated */
	free(data);
	ExitThread(error);
	return error;
}

Project: FreeRDP

static const char* nego_state_string(NEGO_STATE state)
{
	static const char* const NEGO_STATE_STRINGS[] = { "NEGO_STATE_INITIAL", "NEGO_STATE_EXT",
		                                              "NEGO_STATE_NLA",     "NEGO_STATE_TLS",
		                                              "NEGO_STATE_RDP",     "NEGO_STATE_FAIL",
		                                              "NEGO_STATE_FINAL",   "NEGO_STATE_INVALID" };
	if (state >= ARRAYSIZE(NEGO_STATE_STRINGS))
		return NEGO_STATE_STRINGS[ARRAYSIZE(NEGO_STATE_STRINGS) - 1];
	return NEGO_STATE_STRINGS[state];
}

Project: FreeRDP

static const char* protocol_security_string(UINT32 security)
{
	static const char* PROTOCOL_SECURITY_STRINGS[] = { "RDP", "TLS", "NLA", "UNK", "UNK",
		                                               "UNK", "UNK", "UNK", "EXT", "UNK" };
	if (security >= ARRAYSIZE(PROTOCOL_SECURITY_STRINGS))
		return PROTOCOL_SECURITY_STRINGS[ARRAYSIZE(PROTOCOL_SECURITY_STRINGS) - 1];
	return PROTOCOL_SECURITY_STRINGS[security];
}

Project: FreeRDP

BOOL nego_transport_connect(rdpNego* nego)
{
	if (!nego_tcp_connect(nego))
		return FALSE;

	if (nego->TcpConnected && !nego->NegotiateSecurityLayer)
		return nego_security_connect(nego);

	return nego->TcpConnected;
}

Project: FreeRDP

static void create_irp_thread(SERIAL_DEVICE* serial, IRP* irp)
{
	IRP_THREAD_DATA* data = NULL;
	HANDLE irpThread;
	HANDLE previousIrpThread;
	uintptr_t key;
	/* for a test/debug purpose, uncomment the code below to get a
	 * single thread for all IRPs. NB: two IRPs could not be
	 * processed at the same time, typically two concurent
	 * Read/Write operations could block each other. */
	/* serial_process_irp(serial, irp); */
	/* irp->Complete(irp); */
	/* return; */
	/* NOTE: for good or bad, this implementation relies on the
	 * server to avoid a flooding of requests. see also _purge().
	 */
	EnterCriticalSection(&serial->TerminatingIrpThreadsLock);

	while (serial->IrpThreadToBeTerminatedCount > 0)
	{
		/* Cleaning up termitating and pending irp
		 * threads. See also: irp_thread_func() */
		HANDLE irpThread;
		ULONG_PTR* ids;
		int i, nbIds;
		nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids);

		for (i = 0; i < nbIds; i++)
		{
			/* Checking if ids[i] is terminating or pending */
			DWORD waitResult;
			ULONG_PTR id = ids[i];
			irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id);
			/* FIXME: not quite sure a zero timeout is a good thing to check whether a thread is
			 * stil alived or not */
			waitResult = WaitForSingleObject(irpThread, 0);

			if (waitResult == WAIT_OBJECT_0)
			{
				/* terminating thread */
				/* WLog_Print(serial->log, WLOG_DEBUG, "IRP thread with CompletionId=%"PRIuz"
				 * naturally died", id); */
				CloseHandle(irpThread);
				ListDictionary_Remove(serial->IrpThreads, (void*)id);
				serial->IrpThreadToBeTerminatedCount--;
			}
			else if (waitResult != WAIT_TIMEOUT)
			{
				/* unexpected thread state */
				WLog_Print(serial->log, WLOG_WARN,
				           "WaitForSingleObject, got an unexpected result=0x%" PRIX32 "\n",
				           waitResult);
				assert(FALSE);
			}

			/* pending thread (but not yet terminating thread) if waitResult == WAIT_TIMEOUT */
		}

		if (serial->IrpThreadToBeTerminatedCount > 0)
		{
			WLog_Print(serial->log, WLOG_DEBUG, "%" PRIu32 " IRP thread(s) not yet terminated",
			           serial->IrpThreadToBeTerminatedCount);
			Sleep(1); /* 1 ms */
		}

		free(ids);
	}

	LeaveCriticalSection(&serial->TerminatingIrpThreadsLock);
	/* NB: At this point and thanks to the synchronization we're
	 * sure that the incoming IRP uses well a recycled
	 * CompletionId or the server sent again an IRP already posted
	 * which didn't get yet a response (this later server behavior
	 * at least observed with IOCTL_SERIAL_WAIT_ON_MASK and
	 * mstsc.exe).
	 *
	 * FIXME: behavior documented somewhere? behavior not yet
	 * observed with FreeRDP).
	 */
	key = irp->CompletionId;
	previousIrpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)key);

	if (previousIrpThread)
	{
		/* Thread still alived <=> Request still pending */
		WLog_Print(serial->log, WLOG_DEBUG,
		           "IRP recall: IRP with the CompletionId=%" PRIu32 " not yet completed!",
		           irp->CompletionId);
		assert(FALSE); /* unimplemented */
		/* TODO: asserts that previousIrpThread handles well
		 * the same request by checking more details. Need an
		 * access to the IRP object used by previousIrpThread
		 */
		/* TODO: taking over the pending IRP or sending a kind
		 * of wake up signal to accelerate the pending
		 * request
		 *
		 * To be considered:
		 *   if (IoControlCode == IOCTL_SERIAL_WAIT_ON_MASK) {
		 *       pComm->PendingEvents |= SERIAL_EV_FREERDP_*;
		 *   }
		 */
		irp->Discard(irp);
		return;
	}

	if (ListDictionary_Count(serial->IrpThreads) >= MAX_IRP_THREADS)
	{
		WLog_Print(serial->log, WLOG_WARN,
		           "Number of IRP threads threshold reached: %d, keep on anyway",
		           ListDictionary_Count(serial->IrpThreads));
		assert(FALSE); /* unimplemented */
		               /* TODO: MAX_IRP_THREADS has been thought to avoid a
		                * flooding of pending requests. Use
		                * WaitForMultipleObjects() when available in winpr
		                * for threads.
		                */
	}

	/* error_handle to be used ... */
	data = (IRP_THREAD_DATA*)calloc(1, sizeof(IRP_THREAD_DATA));

	if (data == NULL)
	{
		WLog_Print(serial->log, WLOG_WARN, "Could not allocate a new IRP_THREAD_DATA.");
		goto error_handle;
	}

	data->serial = serial;
	data->irp = irp;
	/* data freed by irp_thread_func */
	irpThread = CreateThread(NULL, 0, irp_thread_func, (void*)data, 0, NULL);

	if (irpThread == INVALID_HANDLE_VALUE)
	{
		WLog_Print(serial->log, WLOG_WARN, "Could not allocate a new IRP thread.");
		goto error_handle;
	}

	key = irp->CompletionId;

	if (!ListDictionary_Add(serial->IrpThreads, (void*)key, irpThread))
	{
		WLog_ERR(TAG, "ListDictionary_Add failed!");
		goto error_handle;
	}

	return;
error_handle:
	irp->IoStatus = STATUS_NO_MEMORY;
	irp->Complete(irp);
	free(data);
}

Project: FreeRDP

static DWORD WINAPI printer_thread_func(LPVOID arg)
{
	IRP* irp;
	PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)arg;
	HANDLE obj[] = { printer_dev->event, printer_dev->stopEvent };
	UINT error = CHANNEL_RC_OK;

	while (1)
	{
		DWORD rc = WaitForMultipleObjects(2, obj, FALSE, INFINITE);

		if (rc == WAIT_FAILED)
		{
			error = GetLastError();
			WLog_ERR(TAG, "WaitForMultipleObjects failed with error %" PRIu32 "!", error);
			break;
		}

		if (rc == WAIT_OBJECT_0 + 1)
			break;
		else if (rc != WAIT_OBJECT_0)
			continue;

		ResetEvent(printer_dev->event);
		irp = (IRP*)InterlockedPopEntrySList(printer_dev->pIrpList);

		if (irp == NULL)
		{
			WLog_ERR(TAG, "InterlockedPopEntrySList failed!");
			error = ERROR_INTERNAL_ERROR;
			break;
		}

		if ((error = printer_process_irp(printer_dev, irp)))
		{
			WLog_ERR(TAG, "printer_process_irp failed with error %" PRIu32 "!", error);
			break;
		}
	}

	if (error && printer_dev->rdpcontext)
		setChannelError(printer_dev->rdpcontext, error, "printer_thread_func reported an error");

	ExitThread(error);
	return error;
}

Project: FreeRDP

static BOOL rdg_process_tunnel_response(rdpRdg* rdg, wStream* s)
{
	UINT16 serverVersion, fieldsPresent;
	UINT32 errorCode;
	const char* error;
	WLog_DBG(TAG, "Tunnel response received");

	if (rdg->state != RDG_CLIENT_STATE_TUNNEL_CREATE)
	{
		return FALSE;
	}

	if (Stream_GetRemainingLength(s) < 10)
	{
		WLog_ERR(TAG, "[%s] Short packet %" PRIuz ", expected 10", __FUNCTION__,
		         Stream_GetRemainingLength(s));
		return FALSE;
	}

	Stream_Read_UINT16(s, serverVersion);
	Stream_Read_UINT32(s, errorCode);
	Stream_Read_UINT16(s, fieldsPresent);
	Stream_Seek_UINT16(s); /* reserved */
	error = rpc_error_to_string(errorCode);
	WLog_DBG(TAG, "serverVersion=%" PRId16 ", errorCode=%s, fieldsPresent=%s", serverVersion, error,
	         tunnel_response_fields_present_to_string(fieldsPresent));

	if (FAILED(errorCode))
	{
		WLog_ERR(TAG, "Tunnel creation error %s", error);
		freerdp_set_last_error_log(rdg->context, errorCode);
		return FALSE;
	}

	return rdg_send_tunnel_authorization(rdg);
}

Project: FreeRDP

static UINT printer_register(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, rdpPrinter* printer)
{
	PRINTER_DEVICE* printer_dev;
	UINT error = ERROR_INTERNAL_ERROR;
	printer_dev = (PRINTER_DEVICE*)calloc(1, sizeof(PRINTER_DEVICE));

	if (!printer_dev)
	{
		WLog_ERR(TAG, "calloc failed!");
		return CHANNEL_RC_NO_MEMORY;
	}

	printer_dev->device.data = Stream_New(NULL, 1024);

	if (!printer_dev->device.data)
		goto error_out;

	sprintf_s(printer_dev->port, sizeof(printer_dev->port), "PRN%" PRIdz, printer->id);
	printer_dev->device.type = RDPDR_DTYP_PRINT;
	printer_dev->device.name = printer_dev->port;
	printer_dev->device.IRPRequest = printer_irp_request;
	printer_dev->device.CustomComponentRequest = printer_custom_component;
	printer_dev->device.Free = printer_free;
	printer_dev->rdpcontext = pEntryPoints->rdpcontext;
	printer_dev->printer = printer;
	printer_dev->pIrpList = (WINPR_PSLIST_HEADER)_aligned_malloc(sizeof(WINPR_SLIST_HEADER),
	                                                             MEMORY_ALLOCATION_ALIGNMENT);

	if (!printer_dev->pIrpList)
	{
		WLog_ERR(TAG, "_aligned_malloc failed!");
		error = CHANNEL_RC_NO_MEMORY;
		goto error_out;
	}

	if (!printer_load_from_config(pEntryPoints->rdpcontext->settings, printer, printer_dev))
		goto error_out;

	InitializeSListHead(printer_dev->pIrpList);

	if (!(printer_dev->event = CreateEvent(NULL, TRUE, FALSE, NULL)))
	{
		WLog_ERR(TAG, "CreateEvent failed!");
		error = ERROR_INTERNAL_ERROR;
		goto error_out;
	}

	if (!(printer_dev->stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
	{
		WLog_ERR(TAG, "CreateEvent failed!");
		error = ERROR_INTERNAL_ERROR;
		goto error_out;
	}

	if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)printer_dev)))
	{
		WLog_ERR(TAG, "RegisterDevice failed with error %" PRIu32 "!", error);
		goto error_out;
	}

	if (!(printer_dev->thread =
	          CreateThread(NULL, 0, printer_thread_func, (void*)printer_dev, 0, NULL)))
	{
		WLog_ERR(TAG, "CreateThread failed!");
		error = ERROR_INTERNAL_ERROR;
		goto error_out;
	}

	printer->AddRef(printer);
	return CHANNEL_RC_OK;
error_out:
	printer_free(&printer_dev->device);
	return error;
}

Project: FreeRDP

BOOL nego_send_negotiation_response(rdpNego* nego)
{
	UINT16 length;
	size_t bm, em;
	BOOL status;
	wStream* s;
	BYTE flags;
	rdpSettings* settings;
	status = TRUE;
	settings = nego->transport->settings;
	s = Stream_New(NULL, 512);

	if (!s)
	{
		WLog_ERR(TAG, "Stream_New failed!");
		return FALSE;
	}

	length = TPDU_CONNECTION_CONFIRM_LENGTH;
	bm = Stream_GetPosition(s);
	Stream_Seek(s, length);

	if (nego->SelectedProtocol & PROTOCOL_FAILED_NEGO)
	{
		UINT32 errorCode = (nego->SelectedProtocol & ~PROTOCOL_FAILED_NEGO);
		flags = 0;
		Stream_Write_UINT8(s, TYPE_RDP_NEG_FAILURE);
		Stream_Write_UINT8(s, flags); /* flags */
		Stream_Write_UINT16(s, 8);    /* RDP_NEG_DATA length (8) */
		Stream_Write_UINT32(s, errorCode);
		length += 8;
		status = FALSE;
	}
	else
	{
		flags = EXTENDED_CLIENT_DATA_SUPPORTED;

		if (settings->SupportGraphicsPipeline)
			flags |= DYNVC_GFX_PROTOCOL_SUPPORTED;

		/* RDP_NEG_DATA must be present for TLS, NLA, and RDP */
		Stream_Write_UINT8(s, TYPE_RDP_NEG_RSP);
		Stream_Write_UINT8(s, flags);                   /* flags */
		Stream_Write_UINT16(s, 8);                      /* RDP_NEG_DATA length (8) */
		Stream_Write_UINT32(s, nego->SelectedProtocol); /* selectedProtocol */
		length += 8;
	}

	em = Stream_GetPosition(s);
	Stream_SetPosition(s, bm);
	tpkt_write_header(s, length);
	tpdu_write_connection_confirm(s, length - 5);
	Stream_SetPosition(s, em);
	Stream_SealLength(s);

	if (transport_write(nego->transport, s) < 0)
	{
		Stream_Free(s, TRUE);
		return FALSE;
	}

	Stream_Free(s, TRUE);

	if (status)
	{
		/* update settings with negotiated protocol security */
		settings->RequestedProtocols = nego->RequestedProtocols;
		settings->SelectedProtocol = nego->SelectedProtocol;

		if (settings->SelectedProtocol == PROTOCOL_RDP)
		{
			settings->TlsSecurity = FALSE;
			settings->NlaSecurity = FALSE;
			settings->RdpSecurity = TRUE;
			settings->UseRdpSecurityLayer = TRUE;

			if (settings->EncryptionLevel == ENCRYPTION_LEVEL_NONE)
			{
				/**
				 * If the server implementation did not explicitely set a
				 * encryption level we default to client compatible
				 */
				settings->EncryptionLevel = ENCRYPTION_LEVEL_CLIENT_COMPATIBLE;
			}

			if (settings->LocalConnection)
			{
				/**
				 * Note: This hack was firstly introduced in commit 95f5e115 to
				 * disable the unnecessary encryption with peers connecting to
				 * 127.0.0.1 or local unix sockets.
				 * This also affects connections via port tunnels! (e.g. ssh -L)
				 */
				WLog_INFO(TAG, "Turning off encryption for local peer with standard rdp security");
				settings->UseRdpSecurityLayer = FALSE;
				settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE;
			}

			if (!settings->RdpServerRsaKey && !settings->RdpKeyFile && !settings->RdpKeyContent)
			{
				WLog_ERR(TAG, "Missing server certificate");
				return FALSE;
			}
		}
		else if (settings->SelectedProtocol == PROTOCOL_SSL)
		{
			settings->TlsSecurity = TRUE;
			settings->NlaSecurity = FALSE;
			settings->RdpSecurity = FALSE;
			settings->UseRdpSecurityLayer = FALSE;
			settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE;
		}
		else if (settings->SelectedProtocol == PROTOCOL_HYBRID)
		{
			settings->TlsSecurity = TRUE;
			settings->NlaSecurity = TRUE;
			settings->RdpSecurity = FALSE;
			settings->UseRdpSecurityLayer = FALSE;
			settings->EncryptionLevel = ENCRYPTION_LEVEL_NONE;
		}
	}

	return status;
}

Project: FreeRDP

UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
{
	char* name;
	char* path;
	char* driver;
	RDPDR_SERIAL* device;
#if defined __linux__ && !defined ANDROID
	size_t i, len;
	SERIAL_DEVICE* serial;
#endif /* __linux__ */
	UINT error = CHANNEL_RC_OK;
	device = (RDPDR_SERIAL*)pEntryPoints->device;
	name = device->Name;
	path = device->Path;
	driver = device->Driver;

	if (!name || (name[0] == '*'))
	{
		/* TODO: implement auto detection of serial ports */
		return CHANNEL_RC_OK;
	}

	if ((name && name[0]) && (path && path[0]))
	{
		wLog* log;
		log = WLog_Get("com.freerdp.channel.serial.client");
		WLog_Print(log, WLOG_DEBUG, "initializing");
#ifndef __linux__ /* to be removed */
		WLog_Print(log, WLOG_WARN, "Serial ports redirection not supported on this platform.");
		return CHANNEL_RC_INITIALIZATION_ERROR;
#else /* __linux __ */
		WLog_Print(log, WLOG_DEBUG, "Defining %s as %s", name, path);

		if (!DefineCommDevice(name /* eg: COM1 */, path /* eg: /dev/ttyS0 */))
		{
			DWORD status = GetLastError();
			WLog_ERR(TAG, "DefineCommDevice failed with %08" PRIx32, status);
			return ERROR_INTERNAL_ERROR;
		}

		serial = (SERIAL_DEVICE*)calloc(1, sizeof(SERIAL_DEVICE));

		if (!serial)
		{
			WLog_ERR(TAG, "calloc failed!");
			return CHANNEL_RC_NO_MEMORY;
		}

		serial->log = log;
		serial->device.type = RDPDR_DTYP_SERIAL;
		serial->device.name = name;
		serial->device.IRPRequest = serial_irp_request;
		serial->device.Free = serial_free;
		serial->rdpcontext = pEntryPoints->rdpcontext;
		len = strlen(name);
		serial->device.data = Stream_New(NULL, len + 1);

		if (!serial->device.data)
		{
			WLog_ERR(TAG, "calloc failed!");
			error = CHANNEL_RC_NO_MEMORY;
			goto error_out;
		}

		for (i = 0; i <= len; i++)
			Stream_Write_UINT8(serial->device.data, name[i] < 0 ? '_' : name[i]);

		if (driver != NULL)
		{
			if (_stricmp(driver, "Serial") == 0)
				serial->ServerSerialDriverId = SerialDriverSerialSys;
			else if (_stricmp(driver, "SerCx") == 0)
				serial->ServerSerialDriverId = SerialDriverSerCxSys;
			else if (_stricmp(driver, "SerCx2") == 0)
				serial->ServerSerialDriverId = SerialDriverSerCx2Sys;
			else
			{
				assert(FALSE);
				WLog_Print(serial->log, WLOG_DEBUG,
				           "Unknown server's serial driver: %s. SerCx2 will be used", driver);
				serial->ServerSerialDriverId = SerialDriverSerialSys;
			}
		}
		else
		{
			/* default driver */
			serial->ServerSerialDriverId = SerialDriverSerialSys;
		}

		if (device->Permissive != NULL)
		{
			if (_stricmp(device->Permissive, "permissive") == 0)
			{
				serial->permissive = TRUE;
			}
			else
			{
				WLog_Print(serial->log, WLOG_DEBUG, "Unknown flag: %s", device->Permissive);
				assert(FALSE);
			}
		}

		WLog_Print(serial->log, WLOG_DEBUG, "Server's serial driver: %s (id: %d)", driver,
		           serial->ServerSerialDriverId);
		/* TODO: implement auto detection of the server's serial driver */
		serial->MainIrpQueue = MessageQueue_New(NULL);

		if (!serial->MainIrpQueue)
		{
			WLog_ERR(TAG, "MessageQueue_New failed!");
			error = CHANNEL_RC_NO_MEMORY;
			goto error_out;
		}

		/* IrpThreads content only modified by create_irp_thread() */
		serial->IrpThreads = ListDictionary_New(FALSE);

		if (!serial->IrpThreads)
		{
			WLog_ERR(TAG, "ListDictionary_New failed!");
			error = CHANNEL_RC_NO_MEMORY;
			goto error_out;
		}

		serial->IrpThreadToBeTerminatedCount = 0;
		InitializeCriticalSection(&serial->TerminatingIrpThreadsLock);

		if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)serial)))
		{
			WLog_ERR(TAG, "EntryPoints->RegisterDevice failed with error %" PRIu32 "!", error);
			goto error_out;
		}

		if (!(serial->MainThread =
		          CreateThread(NULL, 0, serial_thread_func, (void*)serial, 0, NULL)))
		{
			WLog_ERR(TAG, "CreateThread failed!");
			error = ERROR_INTERNAL_ERROR;
			goto error_out;
		}

#endif /* __linux __ */
	}

	return error;
error_out:
#ifdef __linux__ /* to be removed */
	ListDictionary_Free(serial->IrpThreads);
	MessageQueue_Free(serial->MainIrpQueue);
	Stream_Free(serial->device.data, TRUE);
	free(serial);
#endif /* __linux __ */
	return error;
}

Project: FreeRDP

static UINT drive_process_irp(DRIVE_DEVICE* drive, IRP* irp)
{
	UINT error;

	if (!drive || !irp)
		return ERROR_INVALID_PARAMETER;

	irp->IoStatus = STATUS_SUCCESS;

	switch (irp->MajorFunction)
	{
		case IRP_MJ_CREATE:
			error = drive_process_irp_create(drive, irp);
			break;

		case IRP_MJ_CLOSE:
			error = drive_process_irp_close(drive, irp);
			break;

		case IRP_MJ_READ:
			error = drive_process_irp_read(drive, irp);
			break;

		case IRP_MJ_WRITE:
			error = drive_process_irp_write(drive, irp);
			break;

		case IRP_MJ_QUERY_INFORMATION:
			error = drive_process_irp_query_information(drive, irp);
			break;

		case IRP_MJ_SET_INFORMATION:
			error = drive_process_irp_set_information(drive, irp);
			break;

		case IRP_MJ_QUERY_VOLUME_INFORMATION:
			error = drive_process_irp_query_volume_information(drive, irp);
			break;

		case IRP_MJ_LOCK_CONTROL:
			error = drive_process_irp_silent_ignore(drive, irp);
			break;

		case IRP_MJ_DIRECTORY_CONTROL:
			error = drive_process_irp_directory_control(drive, irp);
			break;

		case IRP_MJ_DEVICE_CONTROL:
			error = drive_process_irp_device_control(drive, irp);
			break;

		default:
			irp->IoStatus = STATUS_NOT_SUPPORTED;
			error = irp->Complete(irp);
			break;
	}

	return error;
}

Project: FreeRDP

static DWORD WINAPI serial_thread_func(LPVOID arg)
{
	IRP* irp;
	wMessage message;
	SERIAL_DEVICE* serial = (SERIAL_DEVICE*)arg;
	UINT error = CHANNEL_RC_OK;

	while (1)
	{
		if (!MessageQueue_Wait(serial->MainIrpQueue))
		{
			WLog_ERR(TAG, "MessageQueue_Wait failed!");
			error = ERROR_INTERNAL_ERROR;
			break;
		}

		if (!MessageQueue_Peek(serial->MainIrpQueue, &message, TRUE))
		{
			WLog_ERR(TAG, "MessageQueue_Peek failed!");
			error = ERROR_INTERNAL_ERROR;
			break;
		}

		if (message.id == WMQ_QUIT)
		{
			terminate_pending_irp_threads(serial);
			break;
		}

		irp = (IRP*)message.wParam;

		if (irp)
			create_irp_thread(serial, irp);
	}

	if (error && serial->rdpcontext)
		setChannelError(serial->rdpcontext, error, "serial_thread_func reported an error");

	ExitThread(error);
	return error;
}

Project: FreeRDP

void nego_set_preconnection_id(rdpNego* nego, UINT32 PreconnectionId)
{
	nego->PreconnectionId = PreconnectionId;
}

Project: FreeRDP

static UINT rdpei_on_new_channel_connection(IWTSListenerCallback* pListenerCallback,
                                            IWTSVirtualChannel* pChannel, BYTE* Data,
                                            BOOL* pbAccept, IWTSVirtualChannelCallback** ppCallback)
{
	RDPEI_CHANNEL_CALLBACK* callback;
	RDPEI_LISTENER_CALLBACK* listener_callback = (RDPEI_LISTENER_CALLBACK*)pListenerCallback;
	callback = (RDPEI_CHANNEL_CALLBACK*)calloc(1, sizeof(RDPEI_CHANNEL_CALLBACK));

	if (!callback)
	{
		WLog_ERR(TAG, "calloc failed!");
		return CHANNEL_RC_NO_MEMORY;
	}

	callback->iface.OnDataReceived = rdpei_on_data_received;
	callback->iface.OnClose = rdpei_on_close;
	callback->plugin = listener_callback->plugin;
	callback->channel_mgr = listener_callback->channel_mgr;
	callback->channel = pChannel;
	listener_callback->channel_callback = callback;
	*ppCallback = (IWTSVirtualChannelCallback*)callback;
	return CHANNEL_RC_OK;
}

Project: FreeRDP

static int rdg_bio_free(BIO* bio)
{
	WINPR_UNUSED(bio);
	return 1;
}

Project: FreeRDP

BOOL nego_disconnect(rdpNego* nego)
{
	nego->state = NEGO_STATE_INITIAL;
	return nego_transport_disconnect(nego);
}

Project: FreeRDP

static int rdg_bio_puts(BIO* bio, const char* str)
{
	WINPR_UNUSED(bio);
	WINPR_UNUSED(str);
	return -2;
}

Project: FreeRDP

static UINT drive_register_drive_path(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints, const char* name,
                                      const char* path, BOOL automount)
{
	size_t i, length;
	DRIVE_DEVICE* drive;
	UINT error = ERROR_INTERNAL_ERROR;

	if (!pEntryPoints || !name || !path)
	{
		WLog_ERR(TAG, "[%s] Invalid parameters: pEntryPoints=%p, name=%p, path=%p", pEntryPoints,
		         name, path);
		return ERROR_INVALID_PARAMETER;
	}

	if (name[0] && path[0])
	{
		size_t pathLength = strnlen(path, MAX_PATH);
		drive = (DRIVE_DEVICE*)calloc(1, sizeof(DRIVE_DEVICE));

		if (!drive)
		{
			WLog_ERR(TAG, "calloc failed!");
			return CHANNEL_RC_NO_MEMORY;
		}

		drive->device.type = RDPDR_DTYP_FILESYSTEM;
		drive->device.IRPRequest = drive_irp_request;
		drive->device.Free = drive_free;
		drive->rdpcontext = pEntryPoints->rdpcontext;
		drive->automount = automount;
		length = strlen(name);
		drive->device.data = Stream_New(NULL, length + 1);

		if (!drive->device.data)
		{
			WLog_ERR(TAG, "Stream_New failed!");
			error = CHANNEL_RC_NO_MEMORY;
			goto out_error;
		}

		for (i = 0; i < length; i++)
		{
			/* Filter 2.2.1.3 Device Announce Header (DEVICE_ANNOUNCE) forbidden symbols */
			switch (name[i])
			{
				case ':':
				case '<':
				case '>':
				case '\"':
				case '/':
				case '\\':
				case '|':
				case ' ':
					Stream_Write_UINT8(drive->device.data, '_');
					break;
				default:
					Stream_Write_UINT8(drive->device.data, (BYTE)name[i]);
					break;
			}
		}
		Stream_Write_UINT8(drive->device.data, '\0');

		drive->device.name = (const char*)Stream_Buffer(drive->device.data);
		if (!drive->device.name)
			goto out_error;

		if ((pathLength > 1) && (path[pathLength - 1] == '/'))
			pathLength--;

		if (ConvertToUnicode(sys_code_page, 0, path, pathLength, &drive->path, 0) <= 0)
		{
			WLog_ERR(TAG, "ConvertToUnicode failed!");
			error = CHANNEL_RC_NO_MEMORY;
			goto out_error;
		}

		drive->files = ListDictionary_New(TRUE);

		if (!drive->files)
		{
			WLog_ERR(TAG, "ListDictionary_New failed!");
			error = CHANNEL_RC_NO_MEMORY;
			goto out_error;
		}

		ListDictionary_ValueObject(drive->files)->fnObjectFree = drive_file_objfree;
		drive->IrpQueue = MessageQueue_New(NULL);

		if (!drive->IrpQueue)
		{
			WLog_ERR(TAG, "ListDictionary_New failed!");
			error = CHANNEL_RC_NO_MEMORY;
			goto out_error;
		}

		if ((error = pEntryPoints->RegisterDevice(pEntryPoints->devman, (DEVICE*)drive)))
		{
			WLog_ERR(TAG, "RegisterDevice failed with error %" PRIu32 "!", error);
			goto out_error;
		}

		if (!(drive->thread =
		          CreateThread(NULL, 0, drive_thread_func, drive, CREATE_SUSPENDED, NULL)))
		{
			WLog_ERR(TAG, "CreateThread failed!");
			goto out_error;
		}

		ResumeThread(drive->thread);
	}

	return CHANNEL_RC_OK;
out_error:
	drive_free_int(drive);
	return error;
}

Project: FreeRDP

static BOOL printer_save_to_config(const rdpSettings* settings, const char* PortDosName,
                                   size_t PortDosNameLen, const WCHAR* PnPName, size_t PnPNameLen,
                                   const WCHAR* DriverName, size_t DriverNameLen,
                                   const WCHAR* PrinterName, size_t PrintNameLen,
                                   const BYTE* CachedPrinterConfigData, size_t CacheFieldsLen)
{
	BOOL rc = FALSE;
	char* path = get_printer_config_path(settings, PrinterName, PrintNameLen);

	if (!path)
		goto fail;

	if (!printer_write_setting(path, PRN_CONF_PORT, PortDosName, PortDosNameLen))
		goto fail;

	if (!printer_write_setting(path, PRN_CONF_PNP, PnPName, PnPNameLen))
		goto fail;

	if (!printer_write_setting(path, PRN_CONF_DRIVER, DriverName, DriverNameLen))
		goto fail;

	if (!printer_write_setting(path, PRN_CONF_DATA, CachedPrinterConfigData, CacheFieldsLen))
		goto fail;

fail:
	free(path);
	return rc;
}

Project: FreeRDP

static UINT32 _GetLastErrorToIoStatus(SERIAL_DEVICE* serial)
{
	/* http://msdn.microsoft.com/en-us/library/ff547466%28v=vs.85%29.aspx#generic_status_values_for_serial_device_control_requests
	 */
	switch (GetLastError())
	{
		case ERROR_BAD_DEVICE:
			return STATUS_INVALID_DEVICE_REQUEST;

		case ERROR_CALL_NOT_IMPLEMENTED:
			return STATUS_NOT_IMPLEMENTED;

		case ERROR_CANCELLED:
			return STATUS_CANCELLED;

		case ERROR_INSUFFICIENT_BUFFER:
			return STATUS_BUFFER_TOO_SMALL; /* NB: STATUS_BUFFER_SIZE_TOO_SMALL not defined  */

		case ERROR_INVALID_DEVICE_OBJECT_PARAMETER: /* eg: SerCx2.sys' _purge() */
			return STATUS_INVALID_DEVICE_STATE;

		case ERROR_INVALID_HANDLE:
			return STATUS_INVALID_DEVICE_REQUEST;

		case ERROR_INVALID_PARAMETER:
			return STATUS_INVALID_PARAMETER;

		case ERROR_IO_DEVICE:
			return STATUS_IO_DEVICE_ERROR;

		case ERROR_IO_PENDING:
			return STATUS_PENDING;

		case ERROR_NOT_SUPPORTED:
			return STATUS_NOT_SUPPORTED;

		case ERROR_TIMEOUT:
			return STATUS_TIMEOUT;
			/* no default */
	}

	WLog_Print(serial->log, WLOG_DEBUG, "unexpected last-error: 0x%08" PRIX32 "", GetLastError());
	return STATUS_UNSUCCESSFUL;
}

Project: FreeRDP

SEC_WINNT_AUTH_IDENTITY* nego_get_identity(rdpNego* nego)
{
	if (!nego)
		return NULL;

	return nla_get_identity(nego->transport->nla);
}

Project: FreeRDP

static BOOL rdg_send_tunnel_request(rdpRdg* rdg)
{
	wStream* s;
	BOOL status;
	UINT32 packetSize = 16;
	UINT16 fieldsPresent = 0;
	WCHAR* PAACookie = NULL;
	int PAACookieLen = 0;

	if (rdg->extAuth == HTTP_EXTENDED_AUTH_PAA)
	{
		PAACookieLen =
		    ConvertToUnicode(CP_UTF8, 0, rdg->settings->GatewayAccessToken, -1, &PAACookie, 0);

		if (!PAACookie || (PAACookieLen < 0) || (PAACookieLen > UINT16_MAX / 2))
		{
			free(PAACookie);
			return FALSE;
		}

		packetSize += 2 + (UINT32)PAACookieLen * sizeof(WCHAR);
		fieldsPresent = HTTP_TUNNEL_PACKET_FIELD_PAA_COOKIE;
	}

	s = Stream_New(NULL, packetSize);

	if (!s)
	{
		free(PAACookie);
		return FALSE;
	}

	Stream_Write_UINT16(s, PKT_TYPE_TUNNEL_CREATE);        /* Type (2 bytes) */
	Stream_Write_UINT16(s, 0);                             /* Reserved (2 bytes) */
	Stream_Write_UINT32(s, packetSize);                    /* PacketLength (4 bytes) */
	Stream_Write_UINT32(s, HTTP_CAPABILITY_TYPE_QUAR_SOH); /* CapabilityFlags (4 bytes) */
	Stream_Write_UINT16(s, fieldsPresent);                 /* FieldsPresent (2 bytes) */
	Stream_Write_UINT16(s, 0);                             /* Reserved (2 bytes), must be 0 */

	if (PAACookie)
	{
		Stream_Write_UINT16(s, (UINT16)PAACookieLen * 2); /* PAA cookie string length */
		Stream_Write_UTF16_String(s, PAACookie, (size_t)PAACookieLen);
	}

	Stream_SealLength(s);
	status = rdg_write_packet(rdg, s);
	Stream_Free(s, TRUE);
	free(PAACookie);

	if (status)
	{
		rdg->state = RDG_CLIENT_STATE_TUNNEL_CREATE;
	}

	return status;
}

Project: FreeRDP

UINT32 nego_get_selected_protocol(rdpNego* nego)
{
	if (!nego)
		return 0;

	return nego->SelectedProtocol;
}

Project: FreeRDP

static BIO_METHOD* BIO_s_rdg(void)
{
	static BIO_METHOD* bio_methods = NULL;

	if (bio_methods == NULL)
	{
		if (!(bio_methods = BIO_meth_new(BIO_TYPE_TSG, "RDGateway")))
			return NULL;

		BIO_meth_set_write(bio_methods, rdg_bio_write);
		BIO_meth_set_read(bio_methods, rdg_bio_read);
		BIO_meth_set_puts(bio_methods, rdg_bio_puts);
		BIO_meth_set_gets(bio_methods, rdg_bio_gets);
		BIO_meth_set_ctrl(bio_methods, rdg_bio_ctrl);
		BIO_meth_set_create(bio_methods, rdg_bio_new);
		BIO_meth_set_destroy(bio_methods, rdg_bio_free);
	}

	return bio_methods;
}

Project: FreeRDP

static const char* rdpei_eventid_string(UINT16 event)
{
	switch (event)
	{
		case EVENTID_SC_READY:
			return "EVENTID_SC_READY";
		case EVENTID_CS_READY:
			return "EVENTID_CS_READY";
		case EVENTID_TOUCH:
			return "EVENTID_TOUCH";
		case EVENTID_SUSPEND_TOUCH:
			return "EVENTID_SUSPEND_TOUCH";
		case EVENTID_RESUME_TOUCH:
			return "EVENTID_RESUME_TOUCH";
		case EVENTID_DISMISS_HOVERING_CONTACT:
			return "EVENTID_DISMISS_HOVERING_CONTACT";
		default:
			return "EVENTID_UNKNOWN";
	}
}

Project: FreeRDP

static BOOL rdg_read_all(rdpTls* tls, BYTE* buffer, int size)
{
	int status;
	int readCount = 0;
	BYTE* pBuffer = buffer;

	while (readCount < size)
	{
		status = BIO_read(tls->bio, pBuffer, size - readCount);

		if (status <= 0)
		{
			if (!BIO_should_retry(tls->bio))
				return FALSE;

			continue;
		}

		readCount += status;
		pBuffer += status;
	}

	return TRUE;
}

Project: FreeRDP

static BOOL rdg_tls_connect(rdpRdg* rdg, rdpTls* tls, const char* peerAddress, int timeout)
{
	int sockfd = 0;
	long status = 0;
	BIO* socketBio = NULL;
	BIO* bufferedBio = NULL;
	rdpSettings* settings = rdg->settings;
	const char* peerHostname = settings->GatewayHostname;
	UINT16 peerPort = (UINT16)settings->GatewayPort;
	const char *proxyUsername, *proxyPassword;
	BOOL isProxyConnection =
	    proxy_prepare(settings, &peerHostname, &peerPort, &proxyUsername, &proxyPassword);

	if (settings->GatewayPort > UINT16_MAX)
		return FALSE;

	sockfd = freerdp_tcp_connect(rdg->context, settings, peerAddress ? peerAddress : peerHostname,
	                             peerPort, timeout);

	if (sockfd < 0)
	{
		return FALSE;
	}

	socketBio = BIO_new(BIO_s_simple_socket());

	if (!socketBio)
	{
		closesocket((SOCKET)sockfd);
		return FALSE;
	}

	BIO_set_fd(socketBio, sockfd, BIO_CLOSE);
	bufferedBio = BIO_new(BIO_s_buffered_socket());

	if (!bufferedBio)
	{
		BIO_free_all(socketBio);
		return FALSE;
	}

	bufferedBio = BIO_push(bufferedBio, socketBio);
	status = BIO_set_nonblock(bufferedBio, TRUE);

	if (isProxyConnection)
	{
		if (!proxy_connect(settings, bufferedBio, proxyUsername, proxyPassword,
		                   settings->GatewayHostname, (UINT16)settings->GatewayPort))
		{
			BIO_free_all(bufferedBio);
			return FALSE;
		}
	}

	if (!status)
	{
		BIO_free_all(bufferedBio);
		return FALSE;
	}

	tls->hostname = settings->GatewayHostname;
	tls->port = (int)settings->GatewayPort;
	tls->isGatewayTransport = TRUE;
	status = tls_connect(tls, bufferedBio);
	if (status < 1)
	{
		rdpContext* context = rdg->context;
		if (status < 0)
		{
			freerdp_set_last_error_if_not(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
		}
		else
		{
			freerdp_set_last_error_if_not(context, FREERDP_ERROR_CONNECT_CANCELLED);
		}

		return FALSE;
	}
	return (status >= 1);
}

Project: FreeRDP

static rdpPrinterDriver* printer_load_backend(const char* backend)
{
	typedef rdpPrinterDriver* (*backend_load_t)(void);
	union {
		PVIRTUALCHANNELENTRY entry;
		backend_load_t backend;
	} fktconv;

	fktconv.entry = freerdp_load_channel_addin_entry("printer", backend, NULL, 0);
	if (!fktconv.entry)
		return NULL;

	return fktconv.backend();
}

Project: FreeRDP

UINT32 nego_get_requested_protocols(rdpNego* nego)
{
	if (!nego)
		return 0;

	return nego->RequestedProtocols;
}

Project: FreeRDP

BOOL nego_transport_disconnect(rdpNego* nego)
{
	if (nego->TcpConnected)
		transport_disconnect(nego->transport);

	nego->TcpConnected = FALSE;
	nego->SecurityConnected = FALSE;
	return TRUE;
}

Project: FreeRDP

void nego_enable_rdp(rdpNego* nego, BOOL enable_rdp)
{
	WLog_DBG(TAG, "Enabling RDP security: %s", enable_rdp ? "TRUE" : "FALSE");
	nego->EnabledProtocols[PROTOCOL_RDP] = enable_rdp;
}

Project: FreeRDP

BOOL rdg_connect(rdpRdg* rdg, int timeout, BOOL* rpcFallback)
{
	BOOL status;
	SOCKET outConnSocket = 0;
	char* peerAddress = NULL;
	assert(rdg != NULL);
	status =
	    rdg_establish_data_connection(rdg, rdg->tlsOut, "RDG_OUT_DATA", NULL, timeout, rpcFallback);

	if (status)
	{
		/* Establish IN connection with the same peer/server as OUT connection,
		 * even when server hostname resolves to different IP addresses.
		 */
		BIO_get_socket(rdg->tlsOut->underlying, &outConnSocket);
		peerAddress = freerdp_tcp_get_peer_address(outConnSocket);
		status = rdg_establish_data_connection(rdg, rdg->tlsIn, "RDG_IN_DATA", peerAddress, timeout,
		                                       NULL);
		free(peerAddress);
	}

	if (!status)
	{
		rdg->context->rdp->transport->layer = TRANSPORT_LAYER_CLOSED;
		return FALSE;
	}

	status = rdg_tunnel_connect(rdg);

	if (!status)
		return FALSE;

	return TRUE;
}

Project: FreeRDP

static int rdpei_get_version(RdpeiClientContext* context)
{
	RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle;
	return rdpei->version;
}

Project: FreeRDP

static BOOL rdg_handle_ntlm_challenge(rdpNtlm* ntlm, HttpResponse* response)
{
	BOOL continueNeeded = FALSE;
	size_t len;
	const char* token64 = NULL;
	int ntlmTokenLength = 0;
	BYTE* ntlmTokenData = NULL;
	long StatusCode;

	if (!ntlm || !response)
		return FALSE;

	StatusCode = http_response_get_status_code(response);

	if (StatusCode != HTTP_STATUS_DENIED)
	{
		WLog_DBG(TAG, "Unexpected NTLM challenge HTTP status: %ld", StatusCode);
		return FALSE;
	}

	token64 = http_response_get_auth_token(response, "NTLM");

	if (!token64)
		return FALSE;

	len = strlen(token64);

	if (len > INT_MAX)
		return FALSE;

	crypto_base64_decode(token64, (int)len, &ntlmTokenData, &ntlmTokenLength);

	if (ntlmTokenLength < 0)
	{
		free(ntlmTokenData);
		return FALSE;
	}

	if (ntlmTokenData && ntlmTokenLength)
	{
		if (!ntlm_client_set_input_buffer(ntlm, FALSE, ntlmTokenData, (size_t)ntlmTokenLength))
			return FALSE;
	}

	if (!ntlm_authenticate(ntlm, &continueNeeded))
		return FALSE;

	if (continueNeeded)
		return FALSE;

	return TRUE;
}

Project: FreeRDP

static DWORD drive_map_windows_err(DWORD fs_errno)
{
	DWORD rc;

	/* try to return NTSTATUS version of error code */

	switch (fs_errno)
	{
		case STATUS_SUCCESS:
			rc = STATUS_SUCCESS;
			break;

		case ERROR_ACCESS_DENIED:
		case ERROR_SHARING_VIOLATION:
			rc = STATUS_ACCESS_DENIED;
			break;

		case ERROR_FILE_NOT_FOUND:
			rc = STATUS_NO_SUCH_FILE;
			break;

		case ERROR_BUSY_DRIVE:
			rc = STATUS_DEVICE_BUSY;
			break;

		case ERROR_INVALID_DRIVE:
			rc = STATUS_NO_SUCH_DEVICE;
			break;

		case ERROR_NOT_READY:
			rc = STATUS_NO_SUCH_DEVICE;
			break;

		case ERROR_FILE_EXISTS:
		case ERROR_ALREADY_EXISTS:
			rc = STATUS_OBJECT_NAME_COLLISION;
			break;

		case ERROR_INVALID_NAME:
			rc = STATUS_NO_SUCH_FILE;
			break;

		case ERROR_INVALID_HANDLE:
			rc = STATUS_INVALID_HANDLE;
			break;

		case ERROR_NO_MORE_FILES:
			rc = STATUS_NO_MORE_FILES;
			break;

		case ERROR_DIRECTORY:
			rc = STATUS_NOT_A_DIRECTORY;
			break;

		case ERROR_PATH_NOT_FOUND:
			rc = STATUS_OBJECT_PATH_NOT_FOUND;
			break;

		default:
			rc = STATUS_UNSUCCESSFUL;
			WLog_ERR(TAG, "Error code not found: %" PRIu32 "", fs_errno);
			break;
	}

	return rc;
}

Project: FreeRDP

static BOOL rdg_send_http_request(rdpRdg* rdg, rdpTls* tls, const char* method,
                                  const char* transferEncoding)
{
	size_t sz;
	wStream* s = NULL;
	int status = -1;
	s = rdg_build_http_request(rdg, method, transferEncoding);

	if (!s)
		return FALSE;

	sz = Stream_Length(s);

	if (sz <= INT_MAX)
		status = tls_write_all(tls, Stream_Buffer(s), (int)sz);

	Stream_Free(s, TRUE);
	return (status >= 0);
}

Project: FreeRDP

BOOL nego_set_selected_protocol(rdpNego* nego, UINT32 SelectedProtocol)
{
	if (!nego)
		return FALSE;

	nego->SelectedProtocol = SelectedProtocol;
	return TRUE;
}

Project: FreeRDP

static UINT printer_process_irp_create(PRINTER_DEVICE* printer_dev, IRP* irp)
{
	rdpPrintJob* printjob = NULL;

	if (printer_dev->printer)
		printjob =
		    printer_dev->printer->CreatePrintJob(printer_dev->printer, irp->devman->id_sequence++);

	if (printjob)
	{
		Stream_Write_UINT32(irp->output, printjob->id); /* FileId */
	}
	else
	{
		Stream_Write_UINT32(irp->output, 0); /* FileId */
		irp->IoStatus = STATUS_PRINT_QUEUE_FULL;
	}

	return irp->Complete(irp);
}

Project: FreeRDP

static UINT rdpei_recv_suspend_touch_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s)
{
	RdpeiClientContext* rdpei = (RdpeiClientContext*)callback->plugin->pInterface;
	UINT error = CHANNEL_RC_OK;
	IFCALLRET(rdpei->SuspendTouch, error, rdpei);

	if (error)
		WLog_ERR(TAG, "rdpei->SuspendTouch failed with error %" PRIu32 "!", error);

	return error;
}

Project: FreeRDP

static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
{
	UINT error = CHANNEL_RC_OK;
	WLog_Print(serial->log, WLOG_DEBUG,
	           "IRP MajorFunction: 0x%08" PRIX32 " MinorFunction: 0x%08" PRIX32 "\n",
	           irp->MajorFunction, irp->MinorFunction);

	switch (irp->MajorFunction)
	{
		case IRP_MJ_CREATE:
			error = serial_process_irp_create(serial, irp);
			break;

		case IRP_MJ_CLOSE:
			error = serial_process_irp_close(serial, irp);
			break;

		case IRP_MJ_READ:
			if ((error = serial_process_irp_read(serial, irp)))
				WLog_ERR(TAG, "serial_process_irp_read failed with error %" PRIu32 "!", error);

			break;

		case IRP_MJ_WRITE:
			error = serial_process_irp_write(serial, irp);
			break;

		case IRP_MJ_DEVICE_CONTROL:
			if ((error = serial_process_irp_device_control(serial, irp)))
				WLog_ERR(TAG, "serial_process_irp_device_control failed with error %" PRIu32 "!",
				         error);

			break;

		default:
			irp->IoStatus = STATUS_NOT_SUPPORTED;
			break;
	}

	return error;
}

Project: FreeRDP

static UINT rdpei_add_frame(RdpeiClientContext* context)
{
	int i;
	RDPINPUT_CONTACT_DATA* contact;
	RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle;
	rdpei->frame.contactCount = 0;

	for (i = 0; i < rdpei->maxTouchContacts; i++)
	{
		contact = (RDPINPUT_CONTACT_DATA*)&(rdpei->contactPoints[i].data);

		if (rdpei->contactPoints[i].dirty)
		{
			CopyMemory(&(rdpei->contacts[rdpei->frame.contactCount]), contact,
			           sizeof(RDPINPUT_CONTACT_DATA));
			rdpei->contactPoints[i].dirty = FALSE;
			rdpei->frame.contactCount++;
		}
		else if (rdpei->contactPoints[i].active)
		{
			if (contact->contactFlags & CONTACT_FLAG_DOWN)
			{
				contact->contactFlags = CONTACT_FLAG_UPDATE;
				contact->contactFlags |= CONTACT_FLAG_INRANGE;
				contact->contactFlags |= CONTACT_FLAG_INCONTACT;
			}

			CopyMemory(&(rdpei->contacts[rdpei->frame.contactCount]), contact,
			           sizeof(RDPINPUT_CONTACT_DATA));
			rdpei->frame.contactCount++;
		}
	}

	return CHANNEL_RC_OK;
}

Project: FreeRDP

static wStream* rdg_receive_packet(rdpRdg* rdg)
{
	wStream* s;
	const size_t header = sizeof(RdgPacketHeader);
	size_t packetLength;
	assert(header <= INT_MAX);
	s = Stream_New(NULL, 1024);

	if (!s)
		return NULL;

	if (!rdg_read_all(rdg->tlsOut, Stream_Buffer(s), header))
	{
		Stream_Free(s, TRUE);
		return NULL;
	}

	Stream_Seek(s, 4);
	Stream_Read_UINT32(s, packetLength);

	if ((packetLength > INT_MAX) || !Stream_EnsureCapacity(s, packetLength) ||
	    (packetLength < header))
	{
		Stream_Free(s, TRUE);
		return NULL;
	}

	if (!rdg_read_all(rdg->tlsOut, Stream_Buffer(s) + header, (int)packetLength - (int)header))
	{
		Stream_Free(s, TRUE);
		return NULL;
	}

	Stream_SetLength(s, packetLength);
	return s;
}

Project: FreeRDP

static BOOL rdg_write_packet(rdpRdg* rdg, wStream* sPacket)
{
	size_t s;
	int status;
	wStream* sChunk;
	char chunkSize[11];
	sprintf_s(chunkSize, sizeof(chunkSize), "%" PRIXz "\r\n", Stream_Length(sPacket));
	sChunk = Stream_New(NULL, strnlen(chunkSize, sizeof(chunkSize)) + Stream_Length(sPacket) + 2);

	if (!sChunk)
		return FALSE;

	Stream_Write(sChunk, chunkSize, strnlen(chunkSize, sizeof(chunkSize)));
	Stream_Write(sChunk, Stream_Buffer(sPacket), Stream_Length(sPacket));
	Stream_Write(sChunk, "\r\n", 2);
	Stream_SealLength(sChunk);
	s = Stream_Length(sChunk);

	if (s > INT_MAX)
		return FALSE;

	status = tls_write_all(rdg->tlsIn, Stream_Buffer(sChunk), (int)s);
	Stream_Free(sChunk, TRUE);

	if (status < 0)
		return FALSE;

	return TRUE;
}

Project: FreeRDP

rdpRdg* rdg_new(rdpContext* context)
{
	rdpRdg* rdg;
	RPC_CSTR stringUuid;
	char bracedUuid[40];
	RPC_STATUS rpcStatus;

	if (!context)
		return NULL;

	rdg = (rdpRdg*)calloc(1, sizeof(rdpRdg));

	if (rdg)
	{
		rdg->state = RDG_CLIENT_STATE_INITIAL;
		rdg->context = context;
		rdg->settings = rdg->context->settings;
		rdg->extAuth = HTTP_EXTENDED_AUTH_NONE;

		if (rdg->settings->GatewayAccessToken)
			rdg->extAuth = HTTP_EXTENDED_AUTH_PAA;

		UuidCreate(&rdg->guid);
		rpcStatus = UuidToStringA(&rdg->guid, &stringUuid);

		if (rpcStatus == RPC_S_OUT_OF_MEMORY)
			goto rdg_alloc_error;

		sprintf_s(bracedUuid, sizeof(bracedUuid), "{%s}", stringUuid);
		RpcStringFreeA(&stringUuid);
		rdg->tlsOut = tls_new(rdg->settings);

		if (!rdg->tlsOut)
			goto rdg_alloc_error;

		rdg->tlsIn = tls_new(rdg->settings);

		if (!rdg->tlsIn)
			goto rdg_alloc_error;

		rdg->http = http_context_new();

		if (!rdg->http)
			goto rdg_alloc_error;

		if (!http_context_set_uri(rdg->http, "/remoteDesktopGateway/") ||
		    !http_context_set_accept(rdg->http, "*/*") ||
		    !http_context_set_cache_control(rdg->http, "no-cache") ||
		    !http_context_set_pragma(rdg->http, "no-cache") ||
		    !http_context_set_connection(rdg->http, "Keep-Alive") ||
		    !http_context_set_user_agent(rdg->http, "MS-RDGateway/1.0") ||
		    !http_context_set_host(rdg->http, rdg->settings->GatewayHostname) ||
		    !http_context_set_rdg_connection_id(rdg->http, bracedUuid))
		{
			goto rdg_alloc_error;
		}

		if (rdg->extAuth != HTTP_EXTENDED_AUTH_NONE)
		{
			switch (rdg->extAuth)
			{
				case HTTP_EXTENDED_AUTH_PAA:
					if (!http_context_set_rdg_auth_scheme(rdg->http, "PAA"))
						goto rdg_alloc_error;

					break;

				default:
					WLog_DBG(TAG, "RDG extended authentication method %d not supported",
					         rdg->extAuth);
			}
		}

		rdg->frontBio = BIO_new(BIO_s_rdg());

		if (!rdg->frontBio)
			goto rdg_alloc_error;

		BIO_set_data(rdg->frontBio, rdg);
		InitializeCriticalSection(&rdg->writeSection);
	}

	return rdg;
rdg_alloc_error:
	rdg_free(rdg);
	return NULL;
}

Project: FreeRDP

static UINT serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
{
	UINT32 Length;
	UINT64 Offset;
	BYTE* buffer = NULL;
	DWORD nbRead = 0;

	if (Stream_GetRemainingLength(irp->input) < 32)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
	Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
	Stream_Seek(irp->input, 20);            /* Padding (20 bytes) */
	buffer = (BYTE*)calloc(Length, sizeof(BYTE));

	if (buffer == NULL)
	{
		irp->IoStatus = STATUS_NO_MEMORY;
		goto error_handle;
	}

	/* MS-RDPESP 3.2.5.1.4: If the Offset field is not set to 0, the value MUST be ignored
	 * assert(Offset == 0);
	 */
	WLog_Print(serial->log, WLOG_DEBUG, "reading %" PRIu32 " bytes from %s", Length,
	           serial->device.name);

	/* FIXME: CommReadFile to be replaced by ReadFile */
	if (CommReadFile(serial->hComm, buffer, Length, &nbRead, NULL))
	{
		irp->IoStatus = STATUS_SUCCESS;
	}
	else
	{
		WLog_Print(serial->log, WLOG_DEBUG,
		           "read failure to %s, nbRead=%" PRIu32 ", last-error: 0x%08" PRIX32 "",
		           serial->device.name, nbRead, GetLastError());
		irp->IoStatus = _GetLastErrorToIoStatus(serial);
	}

	WLog_Print(serial->log, WLOG_DEBUG, "%" PRIu32 " bytes read from %s", nbRead,
	           serial->device.name);
error_handle:
	Stream_Write_UINT32(irp->output, nbRead); /* Length (4 bytes) */

	if (nbRead > 0)
	{
		if (!Stream_EnsureRemainingCapacity(irp->output, nbRead))
		{
			WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
			free(buffer);
			return CHANNEL_RC_NO_MEMORY;
		}

		Stream_Write(irp->output, buffer, nbRead); /* ReadData */
	}

	free(buffer);
	return CHANNEL_RC_OK;
}

Project: FreeRDP

static void terminate_pending_irp_threads(SERIAL_DEVICE* serial)
{
	ULONG_PTR* ids;
	int i, nbIds;
	nbIds = ListDictionary_GetKeys(serial->IrpThreads, &ids);
	WLog_Print(serial->log, WLOG_DEBUG, "Terminating %d IRP thread(s)", nbIds);

	for (i = 0; i < nbIds; i++)
	{
		HANDLE irpThread;
		ULONG_PTR id = ids[i];
		irpThread = ListDictionary_GetItemValue(serial->IrpThreads, (void*)id);
		TerminateThread(irpThread, 0);

		if (WaitForSingleObject(irpThread, INFINITE) == WAIT_FAILED)
		{
			WLog_ERR(TAG, "WaitForSingleObject failed!");
			continue;
		}

		CloseHandle(irpThread);
		WLog_Print(serial->log, WLOG_DEBUG, "IRP thread terminated, CompletionId %p", (void*)id);
	}

	ListDictionary_Clear(serial->IrpThreads);
	free(ids);
}

Project: FreeRDP

static UINT drive_process_irp_write(DRIVE_DEVICE* drive, IRP* irp)
{
	DRIVE_FILE* file;
	UINT32 Length;
	UINT64 Offset;
	void* ptr;

	if (!drive || !irp || !irp->input || !irp->output || !irp->Complete)
		return ERROR_INVALID_PARAMETER;

	if (Stream_GetRemainingLength(irp->input) < 32)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);
	Stream_Seek(irp->input, 20); /* Padding */
	ptr = Stream_Pointer(irp->input);
	if (!Stream_SafeSeek(irp->input, Length))
		return ERROR_INVALID_DATA;
	file = drive_get_file_by_id(drive, irp->FileId);

	if (!file)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;
	}
	else if (!drive_file_seek(file, Offset))
	{
		irp->IoStatus = drive_map_windows_err(GetLastError());
		Length = 0;
	}
	else if (!drive_file_write(file, ptr, Length))
	{
		irp->IoStatus = drive_map_windows_err(GetLastError());
		Length = 0;
	}

	Stream_Write_UINT32(irp->output, Length);
	Stream_Write_UINT8(irp->output, 0); /* Padding */
	return irp->Complete(irp);
}

Project: FreeRDP

static UINT rdpei_plugin_terminated(IWTSPlugin* pPlugin)
{
	RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)pPlugin;

	if (!pPlugin)
		return ERROR_INVALID_PARAMETER;

	free(rdpei->listener_callback);
	free(rdpei->context);
	free(rdpei);
	return CHANNEL_RC_OK;
}

Project: FreeRDP

static UINT rdpei_touch_update(RdpeiClientContext* context, int externalId, int x, int y,
                               int* contactId)
{
	unsigned int i;
	int contactIdlocal = -1;
	RDPINPUT_CONTACT_DATA contact;
	RDPINPUT_CONTACT_POINT* contactPoint = NULL;
	RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle;
	UINT error = CHANNEL_RC_OK;

	for (i = 0; i < rdpei->maxTouchContacts; i++)
	{
		contactPoint = (RDPINPUT_CONTACT_POINT*)&rdpei->contactPoints[i];

		if (!contactPoint->active)
			continue;

		if (contactPoint->externalId == externalId)
		{
			contactIdlocal = contactPoint->contactId;
			break;
		}
	}

	if (contactIdlocal >= 0)
	{
		ZeroMemory(&contact, sizeof(RDPINPUT_CONTACT_DATA));
		contactPoint->lastX = x;
		contactPoint->lastY = y;
		contact.x = x;
		contact.y = y;
		contact.contactId = (UINT32)contactIdlocal;
		contact.contactFlags |= CONTACT_FLAG_UPDATE;
		contact.contactFlags |= CONTACT_FLAG_INRANGE;
		contact.contactFlags |= CONTACT_FLAG_INCONTACT;
		error = context->AddContact(context, &contact);
	}

	*contactId = contactIdlocal;
	return error;
}

Project: FreeRDP

static int rdg_bio_gets(BIO* bio, char* str, int size)
{
	WINPR_UNUSED(bio);
	WINPR_UNUSED(str);
	WINPR_UNUSED(size);
	return -2;
}

Project: FreeRDP

void nego_enable_tls(rdpNego* nego, BOOL enable_tls)
{
	WLog_DBG(TAG, "Enabling TLS security: %s", enable_tls ? "TRUE" : "FALSE");
	nego->EnabledProtocols[PROTOCOL_SSL] = enable_tls;
}

Project: FreeRDP

static UINT drive_process_irp_query_volume_information(DRIVE_DEVICE* drive, IRP* irp)
{
	UINT32 FsInformationClass;
	wStream* output = NULL;
	char* volumeLabel = { "FREERDP" };
	char* diskType = { "FAT32" };
	WCHAR* outStr = NULL;
	int length;
	DWORD lpSectorsPerCluster;
	DWORD lpBytesPerSector;
	DWORD lpNumberOfFreeClusters;
	DWORD lpTotalNumberOfClusters;
	WIN32_FILE_ATTRIBUTE_DATA wfad;

	if (!drive || !irp)
		return ERROR_INVALID_PARAMETER;

	output = irp->output;

	if (Stream_GetRemainingLength(irp->input) < 4)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, FsInformationClass);
	GetDiskFreeSpaceW(drive->path, &lpSectorsPerCluster, &lpBytesPerSector, &lpNumberOfFreeClusters,
	                  &lpTotalNumberOfClusters);

	switch (FsInformationClass)
	{
		case FileFsVolumeInformation:

			/* http://msdn.microsoft.com/en-us/library/cc232108.aspx */
			if ((length = ConvertToUnicode(sys_code_page, 0, volumeLabel, -1, &outStr, 0) * 2) <= 0)
			{
				WLog_ERR(TAG, "ConvertToUnicode failed!");
				return CHANNEL_RC_NO_MEMORY;
			}

			Stream_Write_UINT32(output, 17 + length); /* Length */

			if (!Stream_EnsureRemainingCapacity(output, 17 + length))
			{
				WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
				free(outStr);
				return CHANNEL_RC_NO_MEMORY;
			}

			GetFileAttributesExW(drive->path, GetFileExInfoStandard, &wfad);
			Stream_Write_UINT32(output, wfad.ftCreationTime.dwLowDateTime); /* VolumeCreationTime */
			Stream_Write_UINT32(output,
			                    wfad.ftCreationTime.dwHighDateTime);      /* VolumeCreationTime */
			Stream_Write_UINT32(output, lpNumberOfFreeClusters & 0xffff); /* VolumeSerialNumber */
			Stream_Write_UINT32(output, length);                          /* VolumeLabelLength */
			Stream_Write_UINT8(output, 0);                                /* SupportsObjects */
			/* Reserved(1), MUST NOT be added! */
			Stream_Write(output, outStr, length); /* VolumeLabel (Unicode) */
			free(outStr);
			break;

		case FileFsSizeInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232107.aspx */
			Stream_Write_UINT32(output, 24); /* Length */

			if (!Stream_EnsureRemainingCapacity(output, 24))
			{
				WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
				return CHANNEL_RC_NO_MEMORY;
			}

			Stream_Write_UINT64(output, lpTotalNumberOfClusters); /* TotalAllocationUnits */
			Stream_Write_UINT64(output, lpNumberOfFreeClusters);  /* AvailableAllocationUnits */
			Stream_Write_UINT32(output, lpSectorsPerCluster);     /* SectorsPerAllocationUnit */
			Stream_Write_UINT32(output, lpBytesPerSector);        /* BytesPerSector */
			break;

		case FileFsAttributeInformation:

			/* http://msdn.microsoft.com/en-us/library/cc232101.aspx */
			if ((length = ConvertToUnicode(sys_code_page, 0, diskType, -1, &outStr, 0) * 2) <= 0)
			{
				WLog_ERR(TAG, "ConvertToUnicode failed!");
				return CHANNEL_RC_NO_MEMORY;
			}

			Stream_Write_UINT32(output, 12 + length); /* Length */

			if (!Stream_EnsureRemainingCapacity(output, 12 + length))
			{
				free(outStr);
				WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
				return CHANNEL_RC_NO_MEMORY;
			}

			Stream_Write_UINT32(output, FILE_CASE_SENSITIVE_SEARCH | FILE_CASE_PRESERVED_NAMES |
			                                FILE_UNICODE_ON_DISK); /* FileSystemAttributes */
			Stream_Write_UINT32(output, MAX_PATH);                 /* MaximumComponentNameLength */
			Stream_Write_UINT32(output, length);                   /* FileSystemNameLength */
			Stream_Write(output, outStr, length);                  /* FileSystemName (Unicode) */
			free(outStr);
			break;

		case FileFsFullSizeInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232104.aspx */
			Stream_Write_UINT32(output, 32); /* Length */

			if (!Stream_EnsureRemainingCapacity(output, 32))
			{
				WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
				return CHANNEL_RC_NO_MEMORY;
			}

			Stream_Write_UINT64(output, lpTotalNumberOfClusters); /* TotalAllocationUnits */
			Stream_Write_UINT64(output,
			                    lpNumberOfFreeClusters); /* CallerAvailableAllocationUnits */
			Stream_Write_UINT64(output, lpNumberOfFreeClusters); /* AvailableAllocationUnits */
			Stream_Write_UINT32(output, lpSectorsPerCluster);    /* SectorsPerAllocationUnit */
			Stream_Write_UINT32(output, lpBytesPerSector);       /* BytesPerSector */
			break;

		case FileFsDeviceInformation:
			/* http://msdn.microsoft.com/en-us/library/cc232109.aspx */
			Stream_Write_UINT32(output, 8); /* Length */

			if (!Stream_EnsureRemainingCapacity(output, 8))
			{
				WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
				return CHANNEL_RC_NO_MEMORY;
			}

			Stream_Write_UINT32(output, FILE_DEVICE_DISK); /* DeviceType */
			Stream_Write_UINT32(output, 0);                /* Characteristics */
			break;

		default:
			irp->IoStatus = STATUS_UNSUCCESSFUL;
			Stream_Write_UINT32(output, 0); /* Length */
			break;
	}

	return irp->Complete(irp);
}

Project: FreeRDP

static void nego_attempt_ext(rdpNego* nego)
{
	nego->RequestedProtocols = PROTOCOL_HYBRID | PROTOCOL_SSL | PROTOCOL_HYBRID_EX;
	WLog_DBG(TAG, "Attempting NLA extended security");

	if (!nego_transport_connect(nego))
	{
		nego->state = NEGO_STATE_FAIL;
		return;
	}

	if (!nego_send_negotiation_request(nego))
	{
		nego->state = NEGO_STATE_FAIL;
		return;
	}

	if (!nego_recv_response(nego))
	{
		nego->state = NEGO_STATE_FAIL;
		return;
	}

	WLog_DBG(TAG, "state: %s", nego_state_string(nego->state));

	if (nego->state != NEGO_STATE_FINAL)
	{
		nego_transport_disconnect(nego);

		if (nego->EnabledProtocols[PROTOCOL_HYBRID])
			nego->state = NEGO_STATE_NLA;
		else if (nego->EnabledProtocols[PROTOCOL_SSL])
			nego->state = NEGO_STATE_TLS;
		else if (nego->EnabledProtocols[PROTOCOL_RDP])
			nego->state = NEGO_STATE_RDP;
		else
			nego->state = NEGO_STATE_FAIL;
	}
}

Project: FreeRDP

BOOL nego_process_negotiation_response(rdpNego* nego, wStream* s)
{
	UINT16 length;
	WLog_DBG(TAG, "RDP_NEG_RSP");

	if (Stream_GetRemainingLength(s) < 7)
	{
		WLog_ERR(TAG, "Invalid RDP_NEG_RSP");
		nego->state = NEGO_STATE_FAIL;
		return FALSE;
	}

	Stream_Read_UINT8(s, nego->flags);
	Stream_Read_UINT16(s, length);
	Stream_Read_UINT32(s, nego->SelectedProtocol);
	nego->state = NEGO_STATE_FINAL;
	return TRUE;
}

Project: FreeRDP

static BOOL rdg_process_keep_alive_packet(rdpRdg* rdg)
{
	int status = -1;
	size_t s;
	wStream* sChunk;
	size_t packetSize = 8;
	char chunkSize[11];
	int chunkLen = sprintf_s(chunkSize, sizeof(chunkSize), "%" PRIxz "\r\n", packetSize);

	if ((chunkLen < 0) || (packetSize > UINT32_MAX))
		return FALSE;

	sChunk = Stream_New(NULL, (size_t)chunkLen + packetSize + 2);

	if (!sChunk)
		return FALSE;

	Stream_Write(sChunk, chunkSize, (size_t)chunkLen);
	Stream_Write_UINT16(sChunk, PKT_TYPE_KEEPALIVE); /* Type */
	Stream_Write_UINT16(sChunk, 0);                  /* Reserved */
	Stream_Write_UINT32(sChunk, (UINT32)packetSize); /* Packet length */
	Stream_Write(sChunk, "\r\n", 2);
	Stream_SealLength(sChunk);
	s = Stream_Length(sChunk);

	if (s <= INT_MAX)
		status = tls_write_all(rdg->tlsIn, Stream_Buffer(sChunk), (int)s);

	Stream_Free(sChunk, TRUE);
	return (status < 0 ? FALSE : TRUE);
}

Project: FreeRDP

void nego_set_cookie_max_length(rdpNego* nego, UINT32 CookieMaxLength)
{
	nego->CookieMaxLength = CookieMaxLength;
}

Project: FreeRDP

static UINT serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
{
	if (Stream_GetRemainingLength(irp->input) < 32)
		return ERROR_INVALID_DATA;

	Stream_Seek(irp->input, 32); /* Padding (32 bytes) */

	if (!CloseHandle(serial->hComm))
	{
		WLog_Print(serial->log, WLOG_WARN, "CloseHandle failure: %s (%" PRIu32 ") closed.",
		           serial->device.name, irp->device->id);
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		goto error_handle;
	}

	WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %" PRIu32 ", FileId: %" PRIu32 ") closed.",
	           serial->device.name, irp->device->id, irp->FileId);
	serial->hComm = NULL;
	irp->IoStatus = STATUS_SUCCESS;
error_handle:
	Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
	return CHANNEL_RC_OK;
}

Project: FreeRDP

static BOOL rdg_process_control_packet(rdpRdg* rdg, int type, size_t packetLength)
{
	wStream* s = NULL;
	size_t readCount = 0;
	int status;
	size_t payloadSize = packetLength - sizeof(RdgPacketHeader);

	if (packetLength < sizeof(RdgPacketHeader))
		return FALSE;

	assert(sizeof(RdgPacketHeader) < INT_MAX);

	if (payloadSize)
	{
		s = Stream_New(NULL, payloadSize);

		if (!s)
			return FALSE;

		while (readCount < payloadSize)
		{
			status =
			    BIO_read(rdg->tlsOut->bio, Stream_Pointer(s), (int)payloadSize - (int)readCount);

			if (status <= 0)
			{
				if (!BIO_should_retry(rdg->tlsOut->bio))
				{
					Stream_Free(s, TRUE);
					return FALSE;
				}

				continue;
			}

			Stream_Seek(s, (size_t)status);
			readCount += (size_t)status;

			if (readCount > INT_MAX)
			{
				Stream_Free(s, TRUE);
				return FALSE;
			}
		}
	}

	switch (type)
	{
		case PKT_TYPE_CLOSE_CHANNEL:
			EnterCriticalSection(&rdg->writeSection);
			status = rdg_process_close_packet(rdg);
			LeaveCriticalSection(&rdg->writeSection);
			break;

		case PKT_TYPE_KEEPALIVE:
			EnterCriticalSection(&rdg->writeSection);
			status = rdg_process_keep_alive_packet(rdg);
			LeaveCriticalSection(&rdg->writeSection);
			break;

		default:
			status = rdg_process_unknown_packet(rdg, type);
			break;
	}

	Stream_Free(s, TRUE);
	return status;
}

Project: FreeRDP

BOOL nego_set_cookie(rdpNego* nego, char* cookie)
{
	if (nego->cookie)
	{
		free(nego->cookie);
		nego->cookie = NULL;
	}

	if (!cookie)
		return TRUE;

	nego->cookie = _strdup(cookie);

	if (!nego->cookie)
		return FALSE;

	return TRUE;
}

Project: FreeRDP

static UINT printer_process_irp_write(PRINTER_DEVICE* printer_dev, IRP* irp)
{
	UINT32 Length;
	UINT64 Offset;
	rdpPrintJob* printjob = NULL;
	UINT error = CHANNEL_RC_OK;
	void* ptr;

	if (Stream_GetRemainingLength(irp->input) < 32)
		return ERROR_INVALID_DATA;
	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);
	Stream_Seek(irp->input, 20); /* Padding */
	ptr = Stream_Pointer(irp->input);
	if (!Stream_SafeSeek(irp->input, Length))
		return ERROR_INVALID_DATA;
	if (printer_dev->printer)
		printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId);

	if (!printjob)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;
	}
	else
	{
		error = printjob->Write(printjob, ptr, Length);
	}

	if (error)
	{
		WLog_ERR(TAG, "printjob->Write failed with error %" PRIu32 "!", error);
		return error;
	}

	Stream_Write_UINT32(irp->output, Length);
	Stream_Write_UINT8(irp->output, 0); /* Padding */
	return irp->Complete(irp);
}

Project: FreeRDP

void nego_enable_nla(rdpNego* nego, BOOL enable_nla)
{
	WLog_DBG(TAG, "Enabling NLA security: %s", enable_nla ? "TRUE" : "FALSE");
	nego->EnabledProtocols[PROTOCOL_HYBRID] = enable_nla;
}

Project: FreeRDP

static BOOL rdg_set_ntlm_auth_header(rdpNtlm* ntlm, HttpRequest* request)
{
	const SecBuffer* ntlmToken = ntlm_client_get_output_buffer(ntlm);
	char* base64NtlmToken = NULL;

	if (ntlmToken)
	{
		if (ntlmToken->cbBuffer > INT_MAX)
			return FALSE;

		base64NtlmToken = crypto_base64_encode(ntlmToken->pvBuffer, (int)ntlmToken->cbBuffer);
	}

	if (base64NtlmToken)
	{
		BOOL rc = http_request_set_auth_scheme(request, "NTLM") &&
		          http_request_set_auth_param(request, base64NtlmToken);
		free(base64NtlmToken);

		if (!rc)
			return FALSE;
	}

	return TRUE;
}

Project: FreeRDP

void nego_free_nla(rdpNego* nego)
{
	if (!nego || !nego->transport)
		return;

	nla_free(nego->transport->nla);
	nego->transport->nla = NULL;
}

Project: FreeRDP

static UINT drive_free_int(DRIVE_DEVICE* drive)
{
	UINT error = CHANNEL_RC_OK;

	if (!drive)
		return ERROR_INVALID_PARAMETER;

	CloseHandle(drive->thread);
	ListDictionary_Free(drive->files);
	MessageQueue_Free(drive->IrpQueue);
	Stream_Free(drive->device.data, TRUE);
	free(drive->path);
	free(drive);
	return error;
}

Project: FreeRDP

void nego_set_preconnection_blob(rdpNego* nego, char* PreconnectionBlob)
{
	nego->PreconnectionBlob = PreconnectionBlob;
}

Project: FreeRDP

static UINT rdpei_send_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s, UINT16 eventId,
                           UINT32 pduLength)
{
	UINT status;
	Stream_SetPosition(s, 0);
	Stream_Write_UINT16(s, eventId);   /* eventId (2 bytes) */
	Stream_Write_UINT32(s, pduLength); /* pduLength (4 bytes) */
	Stream_SetPosition(s, Stream_Length(s));
	status = callback->channel->Write(callback->channel, (UINT32)Stream_Length(s), Stream_Buffer(s),
	                                  NULL);
#ifdef WITH_DEBUG_RDPEI
	WLog_DBG(TAG,
	         "rdpei_send_pdu: eventId: %" PRIu16 " (%s) length: %" PRIu32 " status: %" PRIu32 "",
	         eventId, rdpei_eventid_string(eventId), pduLength, status);
#endif
	return status;
}

Project: FreeRDP

UINT DVCPluginEntry(IDRDYNVC_ENTRY_POINTS* pEntryPoints)
{
	UINT error;
	RDPEI_PLUGIN* rdpei = NULL;
	RdpeiClientContext* context = NULL;
	rdpei = (RDPEI_PLUGIN*)pEntryPoints->GetPlugin(pEntryPoints, "rdpei");

	if (!rdpei)
	{
		size_t size;
		rdpei = (RDPEI_PLUGIN*)calloc(1, sizeof(RDPEI_PLUGIN));

		if (!rdpei)
		{
			WLog_ERR(TAG, "calloc failed!");
			return CHANNEL_RC_NO_MEMORY;
		}

		rdpei->iface.Initialize = rdpei_plugin_initialize;
		rdpei->iface.Connected = NULL;
		rdpei->iface.Disconnected = NULL;
		rdpei->iface.Terminated = rdpei_plugin_terminated;
		rdpei->version = 1;
		rdpei->currentFrameTime = 0;
		rdpei->previousFrameTime = 0;
		rdpei->frame.contacts = (RDPINPUT_CONTACT_DATA*)rdpei->contacts;
		rdpei->maxTouchContacts = 10;
		size = rdpei->maxTouchContacts * sizeof(RDPINPUT_CONTACT_POINT);
		rdpei->contactPoints = (RDPINPUT_CONTACT_POINT*)calloc(1, size);
		rdpei->rdpcontext =
		    ((freerdp*)((rdpSettings*)pEntryPoints->GetRdpSettings(pEntryPoints))->instance)
		        ->context;

		if (!rdpei->contactPoints)
		{
			WLog_ERR(TAG, "calloc failed!");
			error = CHANNEL_RC_NO_MEMORY;
			goto error_out;
		}

		context = (RdpeiClientContext*)calloc(1, sizeof(RdpeiClientContext));

		if (!context)
		{
			WLog_ERR(TAG, "calloc failed!");
			error = CHANNEL_RC_NO_MEMORY;
			goto error_out;
		}

		context->handle = (void*)rdpei;
		context->GetVersion = rdpei_get_version;
		context->AddContact = rdpei_add_contact;
		context->TouchBegin = rdpei_touch_begin;
		context->TouchUpdate = rdpei_touch_update;
		context->TouchEnd = rdpei_touch_end;
		rdpei->iface.pInterface = (void*)context;

		if ((error = pEntryPoints->RegisterPlugin(pEntryPoints, "rdpei", (IWTSPlugin*)rdpei)))
		{
			WLog_ERR(TAG, "EntryPoints->RegisterPlugin failed with error %" PRIu32 "!", error);
			error = CHANNEL_RC_NO_MEMORY;
			goto error_out;
		}

		rdpei->context = context;
	}

	return CHANNEL_RC_OK;
error_out:
	free(context);
	free(rdpei->contactPoints);
	free(rdpei);
	return error;
}

Project: FreeRDP

static const char* tunnel_authorization_response_fields_present_to_string(UINT16 fieldsPresent)
{
	return fields_present_to_string(fieldsPresent, tunnel_authorization_response_fields_present,
	                                ARRAYSIZE(tunnel_authorization_response_fields_present));
}

Project: FreeRDP

static UINT serial_irp_request(DEVICE* device, IRP* irp)
{
	SERIAL_DEVICE* serial = (SERIAL_DEVICE*)device;
	assert(irp != NULL);

	if (irp == NULL)
		return CHANNEL_RC_OK;

	/* NB: ENABLE_ASYNCIO is set, (MS-RDPEFS 2.2.2.7.2) this
	 * allows the server to send multiple simultaneous read or
	 * write requests.
	 */

	if (!MessageQueue_Post(serial->MainIrpQueue, NULL, 0, (void*)irp, NULL))
	{
		WLog_ERR(TAG, "MessageQueue_Post failed!");
		return ERROR_INTERNAL_ERROR;
	}

	return CHANNEL_RC_OK;
}

Project: FreeRDP

void rdg_free(rdpRdg* rdg)
{
	if (!rdg)
		return;

	tls_free(rdg->tlsOut);
	tls_free(rdg->tlsIn);
	http_context_free(rdg->http);
	ntlm_free(rdg->ntlm);

	if (!rdg->attached)
		BIO_free_all(rdg->frontBio);

	DeleteCriticalSection(&rdg->writeSection);
	free(rdg);
}

Project: FreeRDP

static int rdg_write_data_packet(rdpRdg* rdg, const BYTE* buf, int isize)
{
	int status;
	size_t s;
	wStream* sChunk;
	size_t size = (size_t)isize;
	size_t packetSize = size + 10;
	char chunkSize[11];

	if ((isize < 0) || (isize > UINT16_MAX))
		return -1;

	if (size < 1)
		return 0;

	sprintf_s(chunkSize, sizeof(chunkSize), "%" PRIxz "\r\n", packetSize);
	sChunk = Stream_New(NULL, strnlen(chunkSize, sizeof(chunkSize)) + packetSize + 2);

	if (!sChunk)
		return -1;

	Stream_Write(sChunk, chunkSize, strnlen(chunkSize, sizeof(chunkSize)));
	Stream_Write_UINT16(sChunk, PKT_TYPE_DATA);      /* Type */
	Stream_Write_UINT16(sChunk, 0);                  /* Reserved */
	Stream_Write_UINT32(sChunk, (UINT32)packetSize); /* Packet length */
	Stream_Write_UINT16(sChunk, (UINT16)size);       /* Data size */
	Stream_Write(sChunk, buf, size);                 /* Data */
	Stream_Write(sChunk, "\r\n", 2);
	Stream_SealLength(sChunk);
	s = Stream_Length(sChunk);

	if (s > INT_MAX)
		return -1;

	status = tls_write_all(rdg->tlsIn, Stream_Buffer(sChunk), (int)s);
	Stream_Free(sChunk, TRUE);

	if (status < 0)
		return -1;

	return (int)size;
}

Project: FreeRDP

static int rdg_bio_new(BIO* bio)
{
	BIO_set_init(bio, 1);
	BIO_set_flags(bio, BIO_FLAGS_SHOULD_RETRY);
	return 1;
}

Project: FreeRDP

BOOL nego_process_negotiation_request(rdpNego* nego, wStream* s)
{
	BYTE flags;
	UINT16 length;

	if (Stream_GetRemainingLength(s) < 7)
		return FALSE;
	Stream_Read_UINT8(s, flags);
	Stream_Read_UINT16(s, length);
	Stream_Read_UINT32(s, nego->RequestedProtocols);
	WLog_DBG(TAG, "RDP_NEG_REQ: RequestedProtocol: 0x%08" PRIX32 "", nego->RequestedProtocols);
	nego->state = NEGO_STATE_FINAL;
	return TRUE;
}

Project: FreeRDP

static BOOL rdg_process_channel_response(rdpRdg* rdg, wStream* s)
{
	UINT16 fieldsPresent;
	UINT32 errorCode;
	const char* error;
	WLog_DBG(TAG, "Channel response received");

	if (rdg->state != RDG_CLIENT_STATE_CHANNEL_CREATE)
	{
		return FALSE;
	}

	if (Stream_GetRemainingLength(s) < 8)
	{
		WLog_ERR(TAG, "[%s] Short packet %" PRIuz ", expected 8", __FUNCTION__,
		         Stream_GetRemainingLength(s));
		return FALSE;
	}

	Stream_Read_UINT32(s, errorCode);
	Stream_Read_UINT16(s, fieldsPresent);
	Stream_Seek_UINT16(s); /* reserved */
	error = rpc_error_to_string(errorCode);
	WLog_DBG(TAG, "channel response errorCode=%s, fieldsPresent=%s", error,
	         channel_response_fields_present_to_string(fieldsPresent));

	if (FAILED(errorCode))
	{
		WLog_ERR(TAG, "channel response errorCode=%s, fieldsPresent=%s", error,
		         channel_response_fields_present_to_string(fieldsPresent));
		freerdp_set_last_error_log(rdg->context, errorCode);
		return FALSE;
	}

	rdg->state = RDG_CLIENT_STATE_OPENED;
	return TRUE;
}

Project: FreeRDP

static UINT printer_process_irp(PRINTER_DEVICE* printer_dev, IRP* irp)
{
	UINT error;

	switch (irp->MajorFunction)
	{
		case IRP_MJ_CREATE:
			if ((error = printer_process_irp_create(printer_dev, irp)))
			{
				WLog_ERR(TAG, "printer_process_irp_create failed with error %" PRIu32 "!", error);
				return error;
			}

			break;

		case IRP_MJ_CLOSE:
			if ((error = printer_process_irp_close(printer_dev, irp)))
			{
				WLog_ERR(TAG, "printer_process_irp_close failed with error %" PRIu32 "!", error);
				return error;
			}

			break;

		case IRP_MJ_WRITE:
			if ((error = printer_process_irp_write(printer_dev, irp)))
			{
				WLog_ERR(TAG, "printer_process_irp_write failed with error %" PRIu32 "!", error);
				return error;
			}

			break;

		case IRP_MJ_DEVICE_CONTROL:
			if ((error = printer_process_irp_device_control(printer_dev, irp)))
			{
				WLog_ERR(TAG, "printer_process_irp_device_control failed with error %" PRIu32 "!",
				         error);
				return error;
			}

			break;

		default:
			irp->IoStatus = STATUS_NOT_SUPPORTED;
			return irp->Complete(irp);
			break;
	}

	return CHANNEL_RC_OK;
}

Project: FreeRDP

static BOOL rdg_process_packet(rdpRdg* rdg, wStream* s)
{
	BOOL status = TRUE;
	UINT16 type;
	UINT32 packetLength;
	Stream_SetPosition(s, 0);

	if (Stream_GetRemainingLength(s) < 8)
	{
		WLog_ERR(TAG, "[%s] Short packet %" PRIuz ", expected 8", __FUNCTION__,
		         Stream_GetRemainingLength(s));
		return FALSE;
	}

	Stream_Read_UINT16(s, type);
	Stream_Seek_UINT16(s); /* reserved */
	Stream_Read_UINT32(s, packetLength);

	if (Stream_Length(s) < packetLength)
	{
		WLog_ERR(TAG, "[%s] Short packet %" PRIuz ", expected %" PRIuz, __FUNCTION__,
		         Stream_Length(s), packetLength);
		return FALSE;
	}

	switch (type)
	{
		case PKT_TYPE_HANDSHAKE_RESPONSE:
			status = rdg_process_handshake_response(rdg, s);
			break;

		case PKT_TYPE_TUNNEL_RESPONSE:
			status = rdg_process_tunnel_response(rdg, s);
			break;

		case PKT_TYPE_TUNNEL_AUTH_RESPONSE:
			status = rdg_process_tunnel_authorization_response(rdg, s);
			break;

		case PKT_TYPE_CHANNEL_RESPONSE:
			status = rdg_process_channel_response(rdg, s);
			break;

		case PKT_TYPE_DATA:
			WLog_ERR(TAG, "[%s] Unexpected packet type DATA", __FUNCTION__);
			return FALSE;
	}

	return status;
}

Project: FreeRDP

const BYTE* nego_get_routing_token(rdpNego* nego, DWORD* RoutingTokenLength)
{
	if (!nego)
		return NULL;
	if (RoutingTokenLength)
		*RoutingTokenLength = nego->RoutingTokenLength;
	return nego->RoutingToken;
}

Project: FreeRDP

NEGO_STATE nego_get_state(rdpNego* nego)
{
	if (!nego)
		return NEGO_STATE_FAIL;

	return nego->state;
}

Project: FreeRDP

static UINT rdpei_touch_begin(RdpeiClientContext* context, int externalId, int x, int y,
                              int* contactId)
{
	unsigned int i;
	INT64 contactIdlocal = -1;
	RDPINPUT_CONTACT_DATA contact;
	RDPINPUT_CONTACT_POINT* contactPoint = NULL;
	RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle;
	UINT error = CHANNEL_RC_OK;

	/* Create a new contact point in an empty slot */

	for (i = 0; i < rdpei->maxTouchContacts; i++)
	{
		contactPoint = (RDPINPUT_CONTACT_POINT*)&rdpei->contactPoints[i];

		if (!contactPoint->active)
		{
			contactPoint->contactId = i;
			contactIdlocal = contactPoint->contactId;
			contactPoint->externalId = externalId;
			contactPoint->active = TRUE;
			contactPoint->state = RDPINPUT_CONTACT_STATE_ENGAGED;
			break;
		}
	}

	if (contactIdlocal >= 0)
	{
		ZeroMemory(&contact, sizeof(RDPINPUT_CONTACT_DATA));
		contactPoint->lastX = x;
		contactPoint->lastY = y;
		contact.x = x;
		contact.y = y;
		contact.contactId = (UINT32)contactIdlocal;
		contact.contactFlags |= CONTACT_FLAG_DOWN;
		contact.contactFlags |= CONTACT_FLAG_INRANGE;
		contact.contactFlags |= CONTACT_FLAG_INCONTACT;
		error = context->AddContact(context, &contact);
	}

	*contactId = contactIdlocal;
	return error;
}

Project: FreeRDP

BOOL nego_security_connect(rdpNego* nego)
{
	if (!nego->TcpConnected)
	{
		nego->SecurityConnected = FALSE;
	}
	else if (!nego->SecurityConnected)
	{
		if (nego->SelectedProtocol == PROTOCOL_HYBRID)
		{
			WLog_DBG(TAG, "nego_security_connect with PROTOCOL_HYBRID");
			nego->SecurityConnected = transport_connect_nla(nego->transport);
		}
		else if (nego->SelectedProtocol == PROTOCOL_SSL)
		{
			WLog_DBG(TAG, "nego_security_connect with PROTOCOL_SSL");
			nego->SecurityConnected = transport_connect_tls(nego->transport);
		}
		else if (nego->SelectedProtocol == PROTOCOL_RDP)
		{
			WLog_DBG(TAG, "nego_security_connect with PROTOCOL_RDP");
			nego->SecurityConnected = transport_connect_rdp(nego->transport);
		}
		else
		{
			WLog_ERR(TAG,
			         "cannot connect security layer because no protocol has been selected yet.");
		}
	}

	return nego->SecurityConnected;
}

Project: FreeRDP

void nego_init(rdpNego* nego)
{
	nego->state = NEGO_STATE_INITIAL;
	nego->RequestedProtocols = PROTOCOL_RDP;
	nego->CookieMaxLength = DEFAULT_COOKIE_MAX_LENGTH;
	nego->sendNegoData = FALSE;
	nego->flags = 0;
}

Project: FreeRDP

static UINT rdpei_add_contact(RdpeiClientContext* context, const RDPINPUT_CONTACT_DATA* contact)
{
	UINT error;
	RDPINPUT_CONTACT_POINT* contactPoint;
	RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle;

	contactPoint = (RDPINPUT_CONTACT_POINT*)&rdpei->contactPoints[contact->contactId];
	CopyMemory(&(contactPoint->data), contact, sizeof(RDPINPUT_CONTACT_DATA));
	contactPoint->dirty = TRUE;

	error = rdpei_add_frame(context);
	if (error != CHANNEL_RC_OK)
	{
		WLog_ERR(TAG, "rdpei_add_frame failed with error %" PRIu32 "!", error);
		return error;
	}

	if (rdpei->frame.contactCount > 0)
	{
		error = rdpei_send_frame(context);
		if (error != CHANNEL_RC_OK)
		{
			WLog_ERR(TAG, "rdpei_send_frame failed with error %" PRIu32 "!", error);
			return error;
		}
	}
	return CHANNEL_RC_OK;
}

Project: FreeRDP

static UINT rdpei_send_touch_event_pdu(RDPEI_CHANNEL_CALLBACK* callback,
                                       RDPINPUT_TOUCH_FRAME* frame)
{
	UINT status;
	wStream* s;
	UINT32 pduLength;
	pduLength = 64 + (frame->contactCount * 64);
	s = Stream_New(NULL, pduLength);

	if (!s)
	{
		WLog_ERR(TAG, "Stream_New failed!");
		return CHANNEL_RC_NO_MEMORY;
	}

	Stream_Seek(s, RDPINPUT_HEADER_LENGTH);
	/**
	 * the time that has elapsed (in milliseconds) from when the oldest touch frame
	 * was generated to when it was encoded for transmission by the client.
	 */
	rdpei_write_4byte_unsigned(
	    s, (UINT32)frame->frameOffset); /* encodeTime (FOUR_BYTE_UNSIGNED_INTEGER) */
	rdpei_write_2byte_unsigned(s, 1);   /* (frameCount) TWO_BYTE_UNSIGNED_INTEGER */

	if ((status = rdpei_write_touch_frame(s, frame)))
	{
		WLog_ERR(TAG, "rdpei_write_touch_frame failed with error %" PRIu32 "!", status);
		Stream_Free(s, TRUE);
		return status;
	}

	Stream_SealLength(s);
	pduLength = Stream_Length(s);
	status = rdpei_send_pdu(callback, s, EVENTID_TOUCH, pduLength);
	Stream_Free(s, TRUE);
	return status;
}

Project: FreeRDP

static UINT drive_process_irp_query_information(DRIVE_DEVICE* drive, IRP* irp)
{
	DRIVE_FILE* file;
	UINT32 FsInformationClass;

	if (!drive || !irp || !irp->Complete)
		return ERROR_INVALID_PARAMETER;

	if (Stream_GetRemainingLength(irp->input) < 4)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, FsInformationClass);
	file = drive_get_file_by_id(drive, irp->FileId);

	if (!file)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
	}
	else if (!drive_file_query_information(file, FsInformationClass, irp->output))
	{
		irp->IoStatus = drive_map_windows_err(GetLastError());
	}

	return irp->Complete(irp);
}

Project: FreeRDP

static BOOL printer_load_from_config(const rdpSettings* settings, rdpPrinter* printer,
                                     PRINTER_DEVICE* printer_dev)
{
	BOOL res = FALSE;
	WCHAR* wname = NULL;
	size_t wlen;
	char* path = NULL;
	int rc;
	UINT32 flags = 0;
	void* DriverName = NULL;
	UINT32 DriverNameLen = 0;
	void* PnPName = NULL;
	UINT32 PnPNameLen = 0;
	void* CachedPrinterConfigData = NULL;
	UINT32 CachedFieldsLen = 0;
	UINT32 PrinterNameLen = 0;

	if (!settings || !printer)
		return FALSE;

	rc = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &wname, 0);

	if (rc <= 0)
		goto fail;

	wlen = _wcslen(wname) + 1;
	path = get_printer_config_path(settings, wname, wlen * sizeof(WCHAR));
	PrinterNameLen = (wlen + 1) * sizeof(WCHAR);

	if (!path)
		goto fail;

	if (printer->is_default)
		flags |= RDPDR_PRINTER_ANNOUNCE_FLAG_DEFAULTPRINTER;

	if (!printer_read_setting(path, PRN_CONF_PNP, &PnPName, &PnPNameLen))
	{
	}

	if (!printer_read_setting(path, PRN_CONF_DRIVER, &DriverName, &DriverNameLen))
	{
		DriverNameLen =
		    ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, (LPWSTR*)&DriverName, 0) * 2 + 1;
	}

	if (!printer_read_setting(path, PRN_CONF_DATA, &CachedPrinterConfigData, &CachedFieldsLen))
	{
	}

	Stream_SetPosition(printer_dev->device.data, 0);

	if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, 24))
		goto fail;

	Stream_Write_UINT32(printer_dev->device.data, flags);
	Stream_Write_UINT32(printer_dev->device.data, 0);          /* CodePage, reserved */
	Stream_Write_UINT32(printer_dev->device.data, PnPNameLen); /* PnPNameLen */
	Stream_Write_UINT32(printer_dev->device.data, DriverNameLen);
	Stream_Write_UINT32(printer_dev->device.data, PrinterNameLen);
	Stream_Write_UINT32(printer_dev->device.data, CachedFieldsLen);

	if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, PnPNameLen))
		goto fail;

	if (PnPNameLen > 0)
		Stream_Write(printer_dev->device.data, PnPName, PnPNameLen);

	if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, DriverNameLen))
		goto fail;

	Stream_Write(printer_dev->device.data, DriverName, DriverNameLen);

	if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, PrinterNameLen))
		goto fail;

	Stream_Write(printer_dev->device.data, wname, PrinterNameLen);

	if (!Stream_EnsureRemainingCapacity(printer_dev->device.data, CachedFieldsLen))
		goto fail;

	Stream_Write(printer_dev->device.data, CachedPrinterConfigData, CachedFieldsLen);
	res = TRUE;
fail:
	free(path);
	free(wname);
	free(PnPName);
	free(DriverName);
	free(CachedPrinterConfigData);
	return res;
}

Project: FreeRDP

static long rdg_bio_ctrl(BIO* bio, int cmd, long arg1, void* arg2)
{
	long status = -1;
	rdpRdg* rdg = (rdpRdg*)BIO_get_data(bio);
	rdpTls* tlsOut = rdg->tlsOut;
	rdpTls* tlsIn = rdg->tlsIn;

	if (cmd == BIO_CTRL_FLUSH)
	{
		(void)BIO_flush(tlsOut->bio);
		(void)BIO_flush(tlsIn->bio);
		status = 1;
	}
	else if (cmd == BIO_C_SET_NONBLOCK)
	{
		status = 1;
	}
	else if (cmd == BIO_C_READ_BLOCKED)
	{
		BIO* bio = tlsOut->bio;
		status = BIO_read_blocked(bio);
	}
	else if (cmd == BIO_C_WRITE_BLOCKED)
	{
		BIO* bio = tlsIn->bio;
		status = BIO_write_blocked(bio);
	}
	else if (cmd == BIO_C_WAIT_READ)
	{
		int timeout = (int)arg1;
		BIO* bio = tlsOut->bio;

		if (BIO_read_blocked(bio))
			return BIO_wait_read(bio, timeout);
		else if (BIO_write_blocked(bio))
			return BIO_wait_write(bio, timeout);
		else
			status = 1;
	}
	else if (cmd == BIO_C_WAIT_WRITE)
	{
		int timeout = (int)arg1;
		BIO* bio = tlsIn->bio;

		if (BIO_write_blocked(bio))
			status = BIO_wait_write(bio, timeout);
		else if (BIO_read_blocked(bio))
			status = BIO_wait_read(bio, timeout);
		else
			status = 1;
	}
	else if (cmd == BIO_C_GET_EVENT || cmd == BIO_C_GET_FD)
	{
		/*
		 * A note about BIO_C_GET_FD:
		 * Even if two FDs are part of RDG, only one FD can be returned here.
		 *
		 * In FreeRDP, BIO FDs are only used for polling, so it is safe to use the outgoing FD only
		 *
		 * See issue #3602
		 */
		status = BIO_ctrl(tlsOut->bio, cmd, arg1, arg2);
	}

	return status;
}

Project: FreeRDP

void nego_set_gateway_bypass_local(rdpNego* nego, BOOL GatewayBypassLocal)
{
	nego->GatewayBypassLocal = GatewayBypassLocal;
}

Project: FreeRDP

static UINT printer_custom_component(DEVICE* device, UINT16 component, UINT16 packetId, wStream* s)
{
	UINT32 eventID;
	PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device;
	const rdpSettings* settings = printer_dev->rdpcontext->settings;

	if (component != RDPDR_CTYP_PRN)
		return ERROR_INVALID_DATA;

	if (Stream_GetRemainingLength(s) < 4)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(s, eventID);

	switch (packetId)
	{
		case PAKID_PRN_CACHE_DATA:
			switch (eventID)
			{
				case RDPDR_ADD_PRINTER_EVENT:
				{
					char PortDosName[8];
					UINT32 PnPNameLen, DriverNameLen, PrintNameLen, CacheFieldsLen;
					const WCHAR *PnPName, *DriverName, *PrinterName;
					const BYTE* CachedPrinterConfigData;

					if (Stream_GetRemainingLength(s) < 24)
						return ERROR_INVALID_DATA;

					Stream_Read(s, PortDosName, sizeof(PortDosName));
					Stream_Read_UINT32(s, PnPNameLen);
					Stream_Read_UINT32(s, DriverNameLen);
					Stream_Read_UINT32(s, PrintNameLen);
					Stream_Read_UINT32(s, CacheFieldsLen);

					if (Stream_GetRemainingLength(s) < PnPNameLen)
						return ERROR_INVALID_DATA;

					PnPName = (const WCHAR*)Stream_Pointer(s);
					Stream_Seek(s, PnPNameLen);

					if (Stream_GetRemainingLength(s) < DriverNameLen)
						return ERROR_INVALID_DATA;

					DriverName = (const WCHAR*)Stream_Pointer(s);
					Stream_Seek(s, DriverNameLen);

					if (Stream_GetRemainingLength(s) < PrintNameLen)
						return ERROR_INVALID_DATA;

					PrinterName = (const WCHAR*)Stream_Pointer(s);
					Stream_Seek(s, PrintNameLen);

					if (Stream_GetRemainingLength(s) < CacheFieldsLen)
						return ERROR_INVALID_DATA;

					CachedPrinterConfigData = Stream_Pointer(s);
					Stream_Seek(s, CacheFieldsLen);

					if (!printer_save_to_config(settings, PortDosName, sizeof(PortDosName), PnPName,
					                            PnPNameLen, DriverName, DriverNameLen, PrinterName,
					                            PrintNameLen, CachedPrinterConfigData,
					                            CacheFieldsLen))
						return ERROR_INTERNAL_ERROR;
				}
				break;

				case RDPDR_UPDATE_PRINTER_EVENT:
				{
					UINT32 PrinterNameLen, ConfigDataLen;
					const WCHAR* PrinterName;
					const BYTE* ConfigData;

					if (Stream_GetRemainingLength(s) < 8)
						return ERROR_INVALID_DATA;

					Stream_Read_UINT32(s, PrinterNameLen);
					Stream_Read_UINT32(s, ConfigDataLen);

					if (Stream_GetRemainingLength(s) < PrinterNameLen)
						return ERROR_INVALID_DATA;

					PrinterName = (const WCHAR*)Stream_Pointer(s);
					Stream_Seek(s, PrinterNameLen);

					if (Stream_GetRemainingLength(s) < ConfigDataLen)
						return ERROR_INVALID_DATA;

					ConfigData = Stream_Pointer(s);
					Stream_Seek(s, ConfigDataLen);

					if (!printer_update_to_config(settings, PrinterName, PrinterNameLen, ConfigData,
					                              ConfigDataLen))
						return ERROR_INTERNAL_ERROR;
				}
				break;

				case RDPDR_DELETE_PRINTER_EVENT:
				{
					UINT32 PrinterNameLen;
					const WCHAR* PrinterName;

					if (Stream_GetRemainingLength(s) < 4)
						return ERROR_INVALID_DATA;

					Stream_Read_UINT32(s, PrinterNameLen);

					if (Stream_GetRemainingLength(s) < PrinterNameLen)
						return ERROR_INVALID_DATA;

					PrinterName = (const WCHAR*)Stream_Pointer(s);
					Stream_Seek(s, PrinterNameLen);
					printer_remove_config(settings, PrinterName, PrinterNameLen);
				}
				break;

				case RDPDR_RENAME_PRINTER_EVENT:
				{
					UINT32 OldPrinterNameLen, NewPrinterNameLen;
					const WCHAR* OldPrinterName;
					const WCHAR* NewPrinterName;

					if (Stream_GetRemainingLength(s) < 8)
						return ERROR_INVALID_DATA;

					Stream_Read_UINT32(s, OldPrinterNameLen);
					Stream_Read_UINT32(s, NewPrinterNameLen);

					if (Stream_GetRemainingLength(s) < OldPrinterNameLen)
						return ERROR_INVALID_DATA;

					OldPrinterName = (const WCHAR*)Stream_Pointer(s);
					Stream_Seek(s, OldPrinterNameLen);

					if (Stream_GetRemainingLength(s) < NewPrinterNameLen)
						return ERROR_INVALID_DATA;

					NewPrinterName = (const WCHAR*)Stream_Pointer(s);
					Stream_Seek(s, NewPrinterNameLen);

					if (!printer_move_config(settings, OldPrinterName, OldPrinterNameLen,
					                         NewPrinterName, NewPrinterNameLen))
						return ERROR_INTERNAL_ERROR;
				}
				break;

				default:
					WLog_ERR(TAG, "Unknown cache data eventID: 0x%08" PRIX32 "", eventID);
					return ERROR_INVALID_DATA;
			}

			break;

		case PAKID_PRN_USING_XPS:
		{
			UINT32 flags;

			if (Stream_GetRemainingLength(s) < 4)
				return ERROR_INVALID_DATA;

			Stream_Read_UINT32(s, flags);
			WLog_ERR(TAG,
			         "Ignoring unhandled message PAKID_PRN_USING_XPS [printerID=%08" PRIx32
			         ", flags=%08" PRIx32 "]",
			         eventID, flags);
		}
		break;

		default:
			WLog_ERR(TAG, "Unknown printing component packetID: 0x%04" PRIX16 "", packetId);
			return ERROR_INVALID_DATA;
	}

	return CHANNEL_RC_OK;
}

Project: FreeRDP

static UINT rdpei_recv_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s)
{
	UINT16 eventId;
	UINT32 pduLength;
	UINT error;
	if (Stream_GetRemainingLength(s) < 6)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT16(s, eventId);   /* eventId (2 bytes) */
	Stream_Read_UINT32(s, pduLength); /* pduLength (4 bytes) */
#ifdef WITH_DEBUG_RDPEI
	WLog_DBG(TAG, "rdpei_recv_pdu: eventId: %" PRIu16 " (%s) length: %" PRIu32 "", eventId,
	         rdpei_eventid_string(eventId), pduLength);
#endif

	switch (eventId)
	{
		case EVENTID_SC_READY:
			if ((error = rdpei_recv_sc_ready_pdu(callback, s)))
			{
				WLog_ERR(TAG, "rdpei_recv_sc_ready_pdu failed with error %" PRIu32 "!", error);
				return error;
			}

			if ((error = rdpei_send_cs_ready_pdu(callback)))
			{
				WLog_ERR(TAG, "rdpei_send_cs_ready_pdu failed with error %" PRIu32 "!", error);
				return error;
			}

			break;

		case EVENTID_SUSPEND_TOUCH:
			if ((error = rdpei_recv_suspend_touch_pdu(callback, s)))
			{
				WLog_ERR(TAG, "rdpei_recv_suspend_touch_pdu failed with error %" PRIu32 "!", error);
				return error;
			}

			break;

		case EVENTID_RESUME_TOUCH:
			if ((error = rdpei_recv_resume_touch_pdu(callback, s)))
			{
				WLog_ERR(TAG, "rdpei_recv_resume_touch_pdu failed with error %" PRIu32 "!", error);
				return error;
			}

			break;

		default:
			break;
	}

	return CHANNEL_RC_OK;
}

Project: FreeRDP

static BOOL rdg_process_handshake_response(rdpRdg* rdg, wStream* s)
{
	UINT32 errorCode;
	UINT16 serverVersion, extendedAuth;
	BYTE verMajor, verMinor;
	const char* error;
	WLog_DBG(TAG, "Handshake response received");

	if (rdg->state != RDG_CLIENT_STATE_HANDSHAKE)
	{
		return FALSE;
	}

	if (Stream_GetRemainingLength(s) < 10)
	{
		WLog_ERR(TAG, "[%s] Short packet %" PRIuz ", expected 10", __FUNCTION__,
		         Stream_GetRemainingLength(s));
		return FALSE;
	}

	Stream_Read_UINT32(s, errorCode);
	Stream_Read_UINT8(s, verMajor);
	Stream_Read_UINT8(s, verMinor);
	Stream_Read_UINT16(s, serverVersion);
	Stream_Read_UINT16(s, extendedAuth);
	error = rpc_error_to_string(errorCode);
	WLog_DBG(TAG,
	         "errorCode=%s, verMajor=%" PRId8 ", verMinor=%" PRId8 ", serverVersion=%" PRId16
	         ", extendedAuth=%s",
	         error, verMajor, verMinor, serverVersion, extended_auth_to_string(extendedAuth));

	if (FAILED(errorCode))
	{
		WLog_ERR(TAG, "Handshake error %s", error);
		freerdp_set_last_error_log(rdg->context, errorCode);
		return FALSE;
	}

	return rdg_send_tunnel_request(rdg);
}

Project: FreeRDP

static int rdg_bio_write(BIO* bio, const char* buf, int num)
{
	int status;
	rdpRdg* rdg = (rdpRdg*)BIO_get_data(bio);
	BIO_clear_flags(bio, BIO_FLAGS_WRITE);
	EnterCriticalSection(&rdg->writeSection);
	status = rdg_write_data_packet(rdg, (const BYTE*)buf, num);
	LeaveCriticalSection(&rdg->writeSection);

	if (status < 0)
	{
		BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY);
		return -1;
	}
	else if (status < num)
	{
		BIO_set_flags(bio, BIO_FLAGS_WRITE);
		WSASetLastError(WSAEWOULDBLOCK);
	}
	else
	{
		BIO_set_flags(bio, BIO_FLAGS_WRITE);
	}

	return status;
}

Project: FreeRDP

void nego_set_restricted_admin_mode_required(rdpNego* nego, BOOL RestrictedAdminModeRequired)
{
	WLog_DBG(TAG, "Enabling restricted admin mode: %s",
	         RestrictedAdminModeRequired ? "TRUE" : "FALSE");
	nego->RestrictedAdminModeRequired = RestrictedAdminModeRequired;
}

Project: FreeRDP

void nego_enable_ext(rdpNego* nego, BOOL enable_ext)
{
	WLog_DBG(TAG, "Enabling NLA extended security: %s", enable_ext ? "TRUE" : "FALSE");
	nego->EnabledProtocols[PROTOCOL_HYBRID_EX] = enable_ext;
}

Project: FreeRDP

int nego_recv(rdpTransport* transport, wStream* s, void* extra)
{
	BYTE li;
	BYTE type;
	UINT16 length;
	rdpNego* nego = (rdpNego*)extra;

	if (!tpkt_read_header(s, &length))
		return -1;

	if (!tpdu_read_connection_confirm(s, &li, length))
		return -1;

	if (li > 6)
	{
		/* rdpNegData (optional) */
		Stream_Read_UINT8(s, type); /* Type */

		switch (type)
		{
			case TYPE_RDP_NEG_RSP:
				if (!nego_process_negotiation_response(nego, s))
					return -1;
				WLog_DBG(TAG, "selected_protocol: %" PRIu32 "", nego->SelectedProtocol);

				/* enhanced security selected ? */

				if (nego->SelectedProtocol)
				{
					if ((nego->SelectedProtocol == PROTOCOL_HYBRID) &&
					    (!nego->EnabledProtocols[PROTOCOL_HYBRID]))
					{
						nego->state = NEGO_STATE_FAIL;
					}

					if ((nego->SelectedProtocol == PROTOCOL_SSL) &&
					    (!nego->EnabledProtocols[PROTOCOL_SSL]))
					{
						nego->state = NEGO_STATE_FAIL;
					}
				}
				else if (!nego->EnabledProtocols[PROTOCOL_RDP])
				{
					nego->state = NEGO_STATE_FAIL;
				}

				break;

			case TYPE_RDP_NEG_FAILURE:
				if (!nego_process_negotiation_failure(nego, s))
					return -1;
				break;
		}
	}
	else if (li == 6)
	{
		WLog_DBG(TAG, "no rdpNegData");

		if (!nego->EnabledProtocols[PROTOCOL_RDP])
			nego->state = NEGO_STATE_FAIL;
		else
			nego->state = NEGO_STATE_FINAL;
	}
	else
	{
		WLog_ERR(TAG, "invalid negotiation response");
		nego->state = NEGO_STATE_FAIL;
	}

	if (!tpkt_ensure_stream_consumed(s, length))
		return -1;
	return 0;
}

Project: FreeRDP

static const char* channel_response_fields_present_to_string(UINT16 fieldsPresent)
{
	return fields_present_to_string(fieldsPresent, channel_response_fields_present,
	                                ARRAYSIZE(channel_response_fields_present));
}

Project: FreeRDP

static BOOL rdg_tunnel_connect(rdpRdg* rdg)
{
	BOOL status;
	wStream* s;
	rdg_send_handshake(rdg);

	while (rdg->state < RDG_CLIENT_STATE_OPENED)
	{
		status = FALSE;
		s = rdg_receive_packet(rdg);

		if (s)
		{
			status = rdg_process_packet(rdg, s);
			Stream_Free(s, TRUE);
		}

		if (!status)
		{
			rdg->context->rdp->transport->layer = TRANSPORT_LAYER_CLOSED;
			return FALSE;
		}
	}

	return TRUE;
}

Project: FreeRDP

static BOOL printer_read_setting(const char* path, prn_conf_t type, void** data, UINT32* length)
{
	DWORD lowSize, highSize;
	DWORD read = 0;
	BOOL rc = FALSE;
	HANDLE file;
	char* fdata = NULL;
	const char* name = filemap[type];
	char* abs = GetCombinedPath(path, name);

	if (!abs)
		return FALSE;

	file = CreateFileA(abs, GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	free(abs);

	if (file == INVALID_HANDLE_VALUE)
		return FALSE;

	lowSize = GetFileSize(file, &highSize);

	if ((lowSize == INVALID_FILE_SIZE) || (highSize != 0))
		goto fail;

	if (lowSize != 0)
	{
		fdata = malloc(lowSize);

		if (!fdata)
			goto fail;

		rc = ReadFile(file, fdata, lowSize, &read, NULL);

		if (lowSize != read)
			rc = FALSE;
	}

fail:
	CloseHandle(file);

	if (rc && (lowSize <= INT_MAX))
	{
		int blen = 0;
		crypto_base64_decode(fdata, (int)lowSize, (BYTE**)data, &blen);

		if (*data && (blen > 0))
			*length = (UINT32)blen;
		else
		{
			rc = FALSE;
			*length = 0;
		}
	}
	else
	{
		*length = 0;
		*data = NULL;
	}

	free(fdata);
	return rc;
}

Project: FreeRDP

static UINT drive_process_irp_read(DRIVE_DEVICE* drive, IRP* irp)
{
	DRIVE_FILE* file;
	UINT32 Length;
	UINT64 Offset;

	if (!drive || !irp || !irp->output || !irp->Complete)
		return ERROR_INVALID_PARAMETER;

	if (Stream_GetRemainingLength(irp->input) < 12)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, Length);
	Stream_Read_UINT64(irp->input, Offset);
	file = drive_get_file_by_id(drive, irp->FileId);

	if (!file)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Length = 0;
	}
	else if (!drive_file_seek(file, Offset))
	{
		irp->IoStatus = drive_map_windows_err(GetLastError());
		Length = 0;
	}

	if (!Stream_EnsureRemainingCapacity(irp->output, Length + 4))
	{
		WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
		return ERROR_INTERNAL_ERROR;
	}
	else if (Length == 0)
		Stream_Write_UINT32(irp->output, 0);
	else
	{
		BYTE* buffer = Stream_Pointer(irp->output) + sizeof(UINT32);

		if (!drive_file_read(file, buffer, &Length))
		{
			irp->IoStatus = drive_map_windows_err(GetLastError());
			Stream_Write_UINT32(irp->output, 0);
		}
		else
		{
			Stream_Write_UINT32(irp->output, Length);
			Stream_Seek(irp->output, Length);
		}
	}

	return irp->Complete(irp);
}

Project: FreeRDP

BIO* rdg_get_front_bio_and_take_ownership(rdpRdg* rdg)
{
	if (!rdg)
		return NULL;

	rdg->attached = TRUE;
	return rdg->frontBio;
}

Project: FreeRDP

static const char* extended_auth_to_string(UINT16 auth)
{
	if (auth == HTTP_EXTENDED_AUTH_NONE)
		return "HTTP_EXTENDED_AUTH_NONE [0x0000]";

	return fields_present_to_string(auth, extended_auth, ARRAYSIZE(extended_auth));
}

Project: FreeRDP

    DeviceServiceEntry
#endif
    (PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
{
	int i;
	char* name;
	char* driver_name;
	BOOL default_backend = TRUE;
	RDPDR_PRINTER* device = NULL;
	rdpPrinterDriver* driver = NULL;
	UINT error = CHANNEL_RC_OK;

	if (!pEntryPoints || !pEntryPoints->device)
		return ERROR_INVALID_PARAMETER;

	device = (RDPDR_PRINTER*)pEntryPoints->device;
	name = device->Name;
	driver_name = device->DriverName;

	/* Secondary argument is one of the following:
	 *
	 * <driver_name>                ... name of a printer driver
	 * <driver_name>:<backend_name> ... name of a printer driver and local printer backend to use
	 */
	if (driver_name)
	{
		char* sep = strstr(driver_name, ":");
		if (sep)
		{
			const char* backend = sep + 1;
			*sep = '\0';
			driver = printer_load_backend(backend);
			default_backend = FALSE;
		}
	}

	if (!driver && default_backend)
	{
		const char* backend =
#if defined(WITH_CUPS)
		    "cups"
#elif defined(_WIN32)
		    "win"
#else
		    ""
#endif
		    ;

		driver = printer_load_backend(backend);
	}

	if (!driver)
	{
		WLog_ERR(TAG, "Could not get a printer driver!");
		return CHANNEL_RC_INITIALIZATION_ERROR;
	}

	if (name && name[0])
	{
		rdpPrinter* printer = driver->GetPrinter(driver, name, driver_name);

		if (!printer)
		{
			WLog_ERR(TAG, "Could not get printer %s!", name);
			error = CHANNEL_RC_INITIALIZATION_ERROR;
			goto fail;
		}

		if (!printer_save_default_config(pEntryPoints->rdpcontext->settings, printer))
		{
			error = CHANNEL_RC_INITIALIZATION_ERROR;
			printer->ReleaseRef(printer);
			goto fail;
		}

		if ((error = printer_register(pEntryPoints, printer)))
		{
			WLog_ERR(TAG, "printer_register failed with error %" PRIu32 "!", error);
			printer->ReleaseRef(printer);
			goto fail;
		}
	}
	else
	{
		rdpPrinter** printers = driver->EnumPrinters(driver);
		rdpPrinter** current = printers;

		for (i = 0; current[i]; i++)
		{
			rdpPrinter* printer = current[i];

			if ((error = printer_register(pEntryPoints, printer)))
			{
				WLog_ERR(TAG, "printer_register failed with error %" PRIu32 "!", error);
				break;
			}
		}

		driver->ReleaseEnumPrinters(printers);
	}

fail:
	driver->ReleaseRef(driver);

	return error;
}

Project: FreeRDP

static BOOL printer_config_valid(const char* path)
{
	if (!path)
		return FALSE;

	if (!PathFileExistsA(path))
		return FALSE;

	return TRUE;
}

Project: FreeRDP

BOOL nego_send_negotiation_request(rdpNego* nego)
{
	BOOL rc = FALSE;
	wStream* s;
	size_t length;
	size_t bm, em;
	BYTE flags = 0;
	size_t cookie_length;
	s = Stream_New(NULL, 512);

	if (!s)
	{
		WLog_ERR(TAG, "Stream_New failed!");
		return FALSE;
	}

	length = TPDU_CONNECTION_REQUEST_LENGTH;
	bm = Stream_GetPosition(s);
	Stream_Seek(s, length);

	if (nego->RoutingToken)
	{
		Stream_Write(s, nego->RoutingToken, nego->RoutingTokenLength);

		/* Ensure Routing Token is correctly terminated - may already be present in string */

		if ((nego->RoutingTokenLength > 2) &&
		    (nego->RoutingToken[nego->RoutingTokenLength - 2] == 0x0D) &&
		    (nego->RoutingToken[nego->RoutingTokenLength - 1] == 0x0A))
		{
			WLog_DBG(TAG, "Routing token looks correctly terminated - use verbatim");
			length += nego->RoutingTokenLength;
		}
		else
		{
			WLog_DBG(TAG, "Adding terminating CRLF to routing token");
			Stream_Write_UINT8(s, 0x0D); /* CR */
			Stream_Write_UINT8(s, 0x0A); /* LF */
			length += nego->RoutingTokenLength + 2;
		}
	}
	else if (nego->cookie)
	{
		cookie_length = strlen(nego->cookie);

		if (cookie_length > nego->CookieMaxLength)
			cookie_length = nego->CookieMaxLength;

		Stream_Write(s, "Cookie: mstshash=", 17);
		Stream_Write(s, (BYTE*)nego->cookie, cookie_length);
		Stream_Write_UINT8(s, 0x0D); /* CR */
		Stream_Write_UINT8(s, 0x0A); /* LF */
		length += cookie_length + 19;
	}

	WLog_DBG(TAG, "RequestedProtocols: %" PRIu32 "", nego->RequestedProtocols);

	if ((nego->RequestedProtocols > PROTOCOL_RDP) || (nego->sendNegoData))
	{
		/* RDP_NEG_DATA must be present for TLS and NLA */
		if (nego->RestrictedAdminModeRequired)
			flags |= RESTRICTED_ADMIN_MODE_REQUIRED;

		Stream_Write_UINT8(s, TYPE_RDP_NEG_REQ);
		Stream_Write_UINT8(s, flags);
		Stream_Write_UINT16(s, 8);                        /* RDP_NEG_DATA length (8) */
		Stream_Write_UINT32(s, nego->RequestedProtocols); /* requestedProtocols */
		length += 8;
	}

	if (length > UINT16_MAX)
		goto fail;

	em = Stream_GetPosition(s);
	Stream_SetPosition(s, bm);
	tpkt_write_header(s, (UINT16)length);
	tpdu_write_connection_request(s, (UINT16)length - 5);
	Stream_SetPosition(s, em);
	Stream_SealLength(s);
	rc = (transport_write(nego->transport, s) >= 0);
fail:
	Stream_Free(s, TRUE);
	return rc;
}

Project: FreeRDP

static UINT rdpei_recv_sc_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s)
{
	UINT32 protocolVersion;
	Stream_Read_UINT32(s, protocolVersion); /* protocolVersion (4 bytes) */
#if 0

	if (protocolVersion != RDPINPUT_PROTOCOL_V10)
	{
		WLog_ERR(TAG,  "Unknown [MS-RDPEI] protocolVersion: 0x%08"PRIX32"", protocolVersion);
		return -1;
	}

#endif
	return CHANNEL_RC_OK;
}

Project: FreeRDP

BOOL nego_set_target(rdpNego* nego, const char* hostname, UINT16 port)
{
	if (!nego || !hostname)
		return FALSE;

	nego->hostname = hostname;
	nego->port = port;
	return TRUE;
}

Project: FreeRDP

static UINT rdpei_touch_end(RdpeiClientContext* context, int externalId, int x, int y,
                            int* contactId)
{
	unsigned int i;
	int contactIdlocal = -1;
	int tempvalue;
	RDPINPUT_CONTACT_DATA contact;
	RDPINPUT_CONTACT_POINT* contactPoint = NULL;
	RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)context->handle;
	UINT error;

	for (i = 0; i < rdpei->maxTouchContacts; i++)
	{
		contactPoint = (RDPINPUT_CONTACT_POINT*)&rdpei->contactPoints[i];

		if (!contactPoint->active)
			continue;

		if (contactPoint->externalId == externalId)
		{
			contactIdlocal = contactPoint->contactId;
			break;
		}
	}

	if (contactIdlocal >= 0)
	{
		ZeroMemory(&contact, sizeof(RDPINPUT_CONTACT_DATA));

		if ((contactPoint->lastX != x) && (contactPoint->lastY != y))
		{
			if ((error = context->TouchUpdate(context, externalId, x, y, &tempvalue)))
			{
				WLog_ERR(TAG, "context->TouchUpdate failed with error %" PRIu32 "!", error);
				return error;
			}
		}

		contact.x = x;
		contact.y = y;
		contact.contactId = (UINT32)contactIdlocal;
		contact.contactFlags |= CONTACT_FLAG_UP;

		if ((error = context->AddContact(context, &contact)))
		{
			WLog_ERR(TAG, "context->AddContact failed with error %" PRIu32 "!", error);
			return error;
		}

		contactPoint->externalId = 0;
		contactPoint->active = FALSE;
		contactPoint->flags = 0;
		contactPoint->contactId = 0;
		contactPoint->state = RDPINPUT_CONTACT_STATE_OUT_OF_RANGE;
	}

	*contactId = contactIdlocal;
	return CHANNEL_RC_OK;
}

Project: FreeRDP

UINT DeviceServiceEntry(PDEVICE_SERVICE_ENTRY_POINTS pEntryPoints)
{
	RDPDR_DRIVE* drive;
	UINT error;
#ifdef WIN32
	char* dev;
	int len;
	char devlist[512], buf[512];
	char* bufdup;
	char* devdup;
#endif
	drive = (RDPDR_DRIVE*)pEntryPoints->device;
#ifndef WIN32
	sys_code_page = CP_UTF8;

	if (strcmp(drive->Path, "*") == 0)
	{
		/* all drives */
		free(drive->Path);
		drive->Path = _strdup("/");

		if (!drive->Path)
		{
			WLog_ERR(TAG, "_strdup failed!");
			return CHANNEL_RC_NO_MEMORY;
		}
	}
	else if (strcmp(drive->Path, "%") == 0)
	{
		free(drive->Path);
		drive->Path = GetKnownPath(KNOWN_PATH_HOME);

		if (!drive->Path)
		{
			WLog_ERR(TAG, "_strdup failed!");
			return CHANNEL_RC_NO_MEMORY;
		}
	}

	error = drive_register_drive_path(pEntryPoints, drive->Name, drive->Path, drive->automount);
#else
	sys_code_page = GetACP();

	/* Special case: path[0] == '*' -> export all drives */
	/* Special case: path[0] == '%' -> user home dir */
	if (strcmp(drive->Path, "%") == 0)
	{
		GetEnvironmentVariableA("USERPROFILE", buf, sizeof(buf));
		PathCchAddBackslashA(buf, sizeof(buf));
		free(drive->Path);
		drive->Path = _strdup(buf);

		if (!drive->Path)
		{
			WLog_ERR(TAG, "_strdup failed!");
			return CHANNEL_RC_NO_MEMORY;
		}

		error = drive_register_drive_path(pEntryPoints, drive->Name, drive->Path, drive->automount);
	}
	else if (strcmp(drive->Path, "*") == 0)
	{
		int i;
		/* Enumerate all devices: */
		GetLogicalDriveStringsA(sizeof(devlist) - 1, devlist);

		for (dev = devlist, i = 0; *dev; dev += 4, i++)
		{
			if (*dev > 'B')
			{
				/* Suppress disk drives A and B to avoid pesty messages */
				len = sprintf_s(buf, sizeof(buf) - 4, "%s", drive->Name);
				buf[len] = '_';
				buf[len + 1] = dev[0];
				buf[len + 2] = 0;
				buf[len + 3] = 0;

				if (!(bufdup = _strdup(buf)))
				{
					WLog_ERR(TAG, "_strdup failed!");
					return CHANNEL_RC_NO_MEMORY;
				}

				if (!(devdup = _strdup(dev)))
				{
					WLog_ERR(TAG, "_strdup failed!");
					return CHANNEL_RC_NO_MEMORY;
				}

				if ((error = drive_register_drive_path(pEntryPoints, bufdup, devdup, TRUE)))
				{
					break;
				}
			}
		}
	}
	else
	{
		error = drive_register_drive_path(pEntryPoints, drive->Name, drive->Path, drive->automount);
	}

#endif
	return error;
}

Project: FreeRDP

void nego_send(rdpNego* nego)
{
	if (nego->state == NEGO_STATE_EXT)
		nego_attempt_ext(nego);
	else if (nego->state == NEGO_STATE_NLA)
		nego_attempt_nla(nego);
	else if (nego->state == NEGO_STATE_TLS)
		nego_attempt_tls(nego);
	else if (nego->state == NEGO_STATE_RDP)
		nego_attempt_rdp(nego);
	else
		WLog_ERR(TAG, "invalid negotiation state for sending");
}

Project: FreeRDP

static UINT drive_process_irp_directory_control(DRIVE_DEVICE* drive, IRP* irp)
{
	if (!drive || !irp)
		return ERROR_INVALID_PARAMETER;

	switch (irp->MinorFunction)
	{
		case IRP_MN_QUERY_DIRECTORY:
			return drive_process_irp_query_directory(drive, irp);

		case IRP_MN_NOTIFY_CHANGE_DIRECTORY: /* TODO */
			return irp->Discard(irp);

		default:
			irp->IoStatus = STATUS_NOT_SUPPORTED;
			Stream_Write_UINT32(irp->output, 0); /* Length */
			return irp->Complete(irp);
	}

	return CHANNEL_RC_OK;
}

Project: FreeRDP

static DWORD WINAPI drive_thread_func(LPVOID arg)
{
	IRP* irp;
	wMessage message;
	DRIVE_DEVICE* drive = (DRIVE_DEVICE*)arg;
	UINT error = CHANNEL_RC_OK;

	if (!drive)
	{
		error = ERROR_INVALID_PARAMETER;
		goto fail;
	}

	while (1)
	{
		if (!MessageQueue_Wait(drive->IrpQueue))
		{
			WLog_ERR(TAG, "MessageQueue_Wait failed!");
			error = ERROR_INTERNAL_ERROR;
			break;
		}

		if (!MessageQueue_Peek(drive->IrpQueue, &message, TRUE))
		{
			WLog_ERR(TAG, "MessageQueue_Peek failed!");
			error = ERROR_INTERNAL_ERROR;
			break;
		}

		if (message.id == WMQ_QUIT)
			break;

		irp = (IRP*)message.wParam;

		if (irp)
		{
			if ((error = drive_process_irp(drive, irp)))
			{
				WLog_ERR(TAG, "drive_process_irp failed with error %" PRIu32 "!", error);
				break;
			}
		}
	}

fail:

	if (error && drive && drive->rdpcontext)
		setChannelError(drive->rdpcontext, error, "drive_thread_func reported an error");

	ExitThread(error);
	return error;
}

Project: FreeRDP

static UINT serial_free(DEVICE* device)
{
	UINT error;
	SERIAL_DEVICE* serial = (SERIAL_DEVICE*)device;
	WLog_Print(serial->log, WLOG_DEBUG, "freeing");
	MessageQueue_PostQuit(serial->MainIrpQueue, 0);

	if (WaitForSingleObject(serial->MainThread, INFINITE) == WAIT_FAILED)
	{
		error = GetLastError();
		WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "!", error);
		return error;
	}

	CloseHandle(serial->MainThread);

	if (serial->hComm)
		CloseHandle(serial->hComm);

	/* Clean up resources */
	Stream_Free(serial->device.data, TRUE);
	MessageQueue_Free(serial->MainIrpQueue);
	ListDictionary_Free(serial->IrpThreads);
	DeleteCriticalSection(&serial->TerminatingIrpThreadsLock);
	free(serial);
	return CHANNEL_RC_OK;
}

Project: FreeRDP

static DRIVE_FILE* drive_get_file_by_id(DRIVE_DEVICE* drive, UINT32 id)
{
	DRIVE_FILE* file = NULL;
	void* key = (void*)(size_t)id;

	if (!drive)
		return NULL;

	file = (DRIVE_FILE*)ListDictionary_GetItemValue(drive->files, key);
	return file;
}

Project: FreeRDP

static UINT drive_free(DEVICE* device)
{
	DRIVE_DEVICE* drive = (DRIVE_DEVICE*)device;
	UINT error = CHANNEL_RC_OK;

	if (!drive)
		return ERROR_INVALID_PARAMETER;

	if (MessageQueue_PostQuit(drive->IrpQueue, 0) &&
	    (WaitForSingleObject(drive->thread, INFINITE) == WAIT_FAILED))
	{
		error = GetLastError();
		WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);
		return error;
	}

	return drive_free_int(drive);
}

Project: FreeRDP

static BOOL rdg_process_close_packet(rdpRdg* rdg)
{
	int status = -1;
	size_t s;
	wStream* sChunk;
	UINT32 packetSize = 12;
	char chunkSize[11];
	int chunkLen = sprintf_s(chunkSize, sizeof(chunkSize), "%" PRIx32 "\r\n", packetSize);

	if (chunkLen < 0)
		return FALSE;

	sChunk = Stream_New(NULL, (size_t)chunkLen + packetSize + 2);

	if (!sChunk)
		return FALSE;

	Stream_Write(sChunk, chunkSize, (size_t)chunkLen);
	Stream_Write_UINT16(sChunk, PKT_TYPE_CLOSE_CHANNEL_RESPONSE); /* Type */
	Stream_Write_UINT16(sChunk, 0);                               /* Reserved */
	Stream_Write_UINT32(sChunk, packetSize);                      /* Packet length */
	Stream_Write_UINT32(sChunk, 0);                               /* Status code */
	Stream_Write(sChunk, "\r\n", 2);
	Stream_SealLength(sChunk);
	s = Stream_Length(sChunk);

	if (s <= INT_MAX)
		status = tls_write_all(rdg->tlsIn, Stream_Buffer(sChunk), (int)s);

	Stream_Free(sChunk, TRUE);
	return (status < 0 ? FALSE : TRUE);
}

Project: FreeRDP

static BOOL rdg_send_channel_create(rdpRdg* rdg)
{
	wStream* s = NULL;
	BOOL status = FALSE;
	WCHAR* serverName = NULL;
	int serverNameLen =
	    ConvertToUnicode(CP_UTF8, 0, rdg->settings->ServerHostname, -1, &serverName, 0);
	UINT32 packetSize = 16 + ((UINT32)serverNameLen) * 2;

	if ((serverNameLen < 0) || (serverNameLen > UINT16_MAX / 2))
		goto fail;

	s = Stream_New(NULL, packetSize);

	if (!s)
		goto fail;

	Stream_Write_UINT16(s, PKT_TYPE_CHANNEL_CREATE); /* Type (2 bytes) */
	Stream_Write_UINT16(s, 0);                       /* Reserved (2 bytes) */
	Stream_Write_UINT32(s, packetSize);              /* PacketLength (4 bytes) */
	Stream_Write_UINT8(s, 1);                        /* Number of resources. (1 byte) */
	Stream_Write_UINT8(s, 0);                        /* Number of alternative resources (1 byte) */
	Stream_Write_UINT16(s, (UINT16)rdg->settings->ServerPort); /* Resource port (2 bytes) */
	Stream_Write_UINT16(s, 3);                                 /* Protocol number (2 bytes) */
	Stream_Write_UINT16(s, (UINT16)serverNameLen * 2);
	Stream_Write_UTF16_String(s, serverName, (size_t)serverNameLen);
	Stream_SealLength(s);
	status = rdg_write_packet(rdg, s);
fail:
	free(serverName);
	Stream_Free(s, TRUE);

	if (status)
		rdg->state = RDG_CLIENT_STATE_CHANNEL_CREATE;

	return status;
}

Project: FreeRDP

static BOOL rdg_send_tunnel_authorization(rdpRdg* rdg)
{
	wStream* s;
	BOOL status;
	WCHAR* clientName = NULL;
	UINT32 packetSize;
	int clientNameLen =
	    ConvertToUnicode(CP_UTF8, 0, rdg->settings->ClientHostname, -1, &clientName, 0);

	if (!clientName || (clientNameLen < 0) || (clientNameLen > UINT16_MAX / 2))
	{
		free(clientName);
		return FALSE;
	}

	packetSize = 12 + (UINT32)clientNameLen * sizeof(WCHAR);
	s = Stream_New(NULL, packetSize);

	if (!s)
	{
		free(clientName);
		return FALSE;
	}

	Stream_Write_UINT16(s, PKT_TYPE_TUNNEL_AUTH);      /* Type (2 bytes) */
	Stream_Write_UINT16(s, 0);                         /* Reserved (2 bytes) */
	Stream_Write_UINT32(s, packetSize);                /* PacketLength (4 bytes) */
	Stream_Write_UINT16(s, 0);                         /* FieldsPresent (2 bytes) */
	Stream_Write_UINT16(s, (UINT16)clientNameLen * 2); /* Client name string length */
	Stream_Write_UTF16_String(s, clientName, (size_t)clientNameLen);
	Stream_SealLength(s);
	status = rdg_write_packet(rdg, s);
	Stream_Free(s, TRUE);
	free(clientName);

	if (status)
	{
		rdg->state = RDG_CLIENT_STATE_TUNNEL_AUTHORIZE;
	}

	return status;
}

Project: FreeRDP

static BOOL rdg_skip_seed_payload(rdpTls* tls, SSIZE_T lastResponseLength)
{
	BYTE seed_payload[10];
	const size_t size = sizeof(seed_payload);

	assert(size < SSIZE_MAX);

	/* Per [MS-TSGU] 3.3.5.1 step 4, after final OK response RDG server sends
	 * random "seed" payload of limited size. In practice it's 10 bytes.
	 */
	if (lastResponseLength < (SSIZE_T)size)
	{
		if (!rdg_read_all(tls, seed_payload, size - lastResponseLength))
		{
			return FALSE;
		}
	}

	return TRUE;
}

Project: FreeRDP

static BOOL rdg_get_gateway_credentials(rdpContext* context)
{
	rdpSettings* settings = context->settings;
	freerdp* instance = context->instance;

	if (!settings->GatewayPassword || !settings->GatewayUsername ||
	    !strlen(settings->GatewayPassword) || !strlen(settings->GatewayUsername))
	{
		if (freerdp_shall_disconnect(instance))
			return FALSE;

		if (!instance->GatewayAuthenticate)
		{
			freerdp_set_last_error_log(context, FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS);
			return FALSE;
		}
		else
		{
			BOOL proceed =
			    instance->GatewayAuthenticate(instance, &settings->GatewayUsername,
			                                  &settings->GatewayPassword, &settings->GatewayDomain);

			if (!proceed)
			{
				freerdp_set_last_error_log(context,
				                           FREERDP_ERROR_CONNECT_NO_OR_MISSING_CREDENTIALS);
				return FALSE;
			}

			if (settings->GatewayUseSameCredentials)
			{
				if (settings->GatewayUsername)
				{
					free(settings->Username);

					if (!(settings->Username = _strdup(settings->GatewayUsername)))
						return FALSE;
				}

				if (settings->GatewayDomain)
				{
					free(settings->Domain);

					if (!(settings->Domain = _strdup(settings->GatewayDomain)))
						return FALSE;
				}

				if (settings->GatewayPassword)
				{
					free(settings->Password);

					if (!(settings->Password = _strdup(settings->GatewayPassword)))
						return FALSE;
				}
			}
		}
	}

	return TRUE;
}

Project: FreeRDP

static BOOL rdg_ntlm_init(rdpRdg* rdg, rdpTls* tls)
{
	BOOL continueNeeded = FALSE;
	rdpContext* context = rdg->context;
	rdpSettings* settings = context->settings;
	rdg->ntlm = ntlm_new();

	if (!rdg->ntlm)
		return FALSE;

	if (!rdg_get_gateway_credentials(context))
		return FALSE;

	if (!ntlm_client_init(rdg->ntlm, TRUE, settings->GatewayUsername, settings->GatewayDomain,
	                      settings->GatewayPassword, tls->Bindings))
		return FALSE;

	if (!ntlm_client_make_spn(rdg->ntlm, _T("HTTP"), settings->GatewayHostname))
		return FALSE;

	if (!ntlm_authenticate(rdg->ntlm, &continueNeeded))
		return FALSE;

	return continueNeeded;
}

Project: FreeRDP

static UINT rdpei_on_close(IWTSVirtualChannelCallback* pChannelCallback)
{
	RDPEI_CHANNEL_CALLBACK* callback = (RDPEI_CHANNEL_CALLBACK*)pChannelCallback;
	free(callback);
	return CHANNEL_RC_OK;
}

Project: FreeRDP

static BOOL printer_save_default_config(const rdpSettings* settings, rdpPrinter* printer)
{
	BOOL res = FALSE;
	WCHAR* wname = NULL;
	WCHAR* driver = NULL;
	size_t wlen, dlen;
	char* path = NULL;
	int rc;

	if (!settings || !printer)
		return FALSE;

	rc = ConvertToUnicode(CP_UTF8, 0, printer->name, -1, &wname, 0);

	if (rc <= 0)
		goto fail;

	rc = ConvertToUnicode(CP_UTF8, 0, printer->driver, -1, &driver, 0);

	if (rc <= 0)
		goto fail;

	wlen = _wcslen(wname) + 1;
	dlen = _wcslen(driver) + 1;
	path = get_printer_config_path(settings, wname, wlen * sizeof(WCHAR));

	if (!path)
		goto fail;

	if (dlen > 1)
	{
		if (!printer_write_setting(path, PRN_CONF_DRIVER, driver, dlen * sizeof(WCHAR)))
			goto fail;
	}

	res = TRUE;
fail:
	free(path);
	free(wname);
	free(driver);
	return res;
}

Project: FreeRDP

BOOL nego_recv_response(rdpNego* nego)
{
	int status;
	wStream* s;
	s = Stream_New(NULL, 1024);

	if (!s)
	{
		WLog_ERR(TAG, "Stream_New failed!");
		return FALSE;
	}

	status = transport_read_pdu(nego->transport, s);

	if (status < 0)
	{
		Stream_Free(s, TRUE);
		return FALSE;
	}

	status = nego_recv(nego->transport, s, nego);
	Stream_Free(s, TRUE);

	if (status < 0)
		return FALSE;

	return TRUE;
}

Project: FreeRDP

BOOL nego_set_state(rdpNego* nego, NEGO_STATE state)
{
	if (!nego)
		return FALSE;

	nego->state = state;
	return TRUE;
}

Project: FreeRDP

void nego_set_send_preconnection_pdu(rdpNego* nego, BOOL SendPreconnectionPdu)
{
	nego->SendPreconnectionPdu = SendPreconnectionPdu;
}

Project: FreeRDP

static const char* tunnel_response_fields_present_to_string(UINT16 fieldsPresent)
{
	return fields_present_to_string(fieldsPresent, tunnel_response_fields_present,
	                                ARRAYSIZE(tunnel_response_fields_present));
}

Project: FreeRDP

static UINT printer_process_irp_close(PRINTER_DEVICE* printer_dev, IRP* irp)
{
	rdpPrintJob* printjob = NULL;

	if (printer_dev->printer)
		printjob = printer_dev->printer->FindPrintJob(printer_dev->printer, irp->FileId);

	if (!printjob)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
	}
	else
	{
		printjob->Close(printjob);
	}

	Stream_Zero(irp->output, 4); /* Padding(4) */
	return irp->Complete(irp);
}

Project: FreeRDP

static BOOL nego_read_request_token_or_cookie(rdpNego* nego, wStream* s)
{
	/* routingToken and cookie are optional and mutually exclusive!
	 *
	 * routingToken (variable): An optional and variable-length routing
	 * token (used for load balancing) terminated by a 0x0D0A two-byte
	 * sequence: (check [MSFT-SDLBTS] for details!)
	 * Cookie:[space]msts=[ip address].[port].[reserved][\x0D\x0A]
	 *
	 * cookie (variable): An optional and variable-length ANSI character
	 * string terminated by a 0x0D0A two-byte sequence:
	 * Cookie:[space]mstshash=[ANSISTRING][\x0D\x0A]
	 */
	BYTE* str = NULL;
	UINT16 crlf = 0;
	size_t pos, len;
	BOOL result = FALSE;
	BOOL isToken = FALSE;
	size_t remain = Stream_GetRemainingLength(s);
	str = Stream_Pointer(s);
	pos = Stream_GetPosition(s);

	/* minimum length for token is 15 */
	if (remain < 15)
		return TRUE;

	if (memcmp(Stream_Pointer(s), "Cookie: mstshash=", 17) != 0)
	{
		isToken = TRUE;
	}
	else
	{
		/* not a token, minimum length for cookie is 19 */
		if (remain < 19)
			return TRUE;

		Stream_Seek(s, 17);
	}

	while ((remain = Stream_GetRemainingLength(s)) >= 2)
	{
		Stream_Read_UINT16(s, crlf);

		if (crlf == 0x0A0D)
			break;

		Stream_Rewind(s, 1);
	}

	if (crlf == 0x0A0D)
	{
		Stream_Rewind(s, 2);
		len = Stream_GetPosition(s) - pos;
		remain = Stream_GetRemainingLength(s);
		Stream_Write_UINT16(s, 0);

		if (strnlen((char*)str, len) == len)
		{
			if (isToken)
				result = nego_set_routing_token(nego, str, len);
			else
				result = nego_set_cookie(nego, (char*)str);
		}
	}

	if (!result)
	{
		Stream_SetPosition(s, pos);
		WLog_ERR(TAG, "invalid %s received", isToken ? "routing token" : "cookie");
	}
	else
	{
		WLog_DBG(TAG, "received %s [%s]", isToken ? "routing token" : "cookie", str);
	}

	return result;
}

Project: FreeRDP

static void rdpei_print_contact_flags(UINT32 contactFlags)
{
	if (contactFlags & CONTACT_FLAG_DOWN)
		WLog_DBG(TAG, " CONTACT_FLAG_DOWN");

	if (contactFlags & CONTACT_FLAG_UPDATE)
		WLog_DBG(TAG, " CONTACT_FLAG_UPDATE");

	if (contactFlags & CONTACT_FLAG_UP)
		WLog_DBG(TAG, " CONTACT_FLAG_UP");

	if (contactFlags & CONTACT_FLAG_INRANGE)
		WLog_DBG(TAG, " CONTACT_FLAG_INRANGE");

	if (contactFlags & CONTACT_FLAG_INCONTACT)
		WLog_DBG(TAG, " CONTACT_FLAG_INCONTACT");

	if (contactFlags & CONTACT_FLAG_CANCELED)
		WLog_DBG(TAG, " CONTACT_FLAG_CANCELED");
}

Project: FreeRDP

static UINT serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
{
	DWORD DesiredAccess;
	DWORD SharedAccess;
	DWORD CreateDisposition;
	UINT32 PathLength;

	if (Stream_GetRemainingLength(irp->input) < 32)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, DesiredAccess);     /* DesiredAccess (4 bytes) */
	Stream_Seek_UINT64(irp->input);                    /* AllocationSize (8 bytes) */
	Stream_Seek_UINT32(irp->input);                    /* FileAttributes (4 bytes) */
	Stream_Read_UINT32(irp->input, SharedAccess);      /* SharedAccess (4 bytes) */
	Stream_Read_UINT32(irp->input, CreateDisposition); /* CreateDisposition (4 bytes) */
	Stream_Seek_UINT32(irp->input);                    /* CreateOptions (4 bytes) */
	Stream_Read_UINT32(irp->input, PathLength);        /* PathLength (4 bytes) */

	if (!Stream_SafeSeek(irp->input, PathLength)) /* Path (variable) */
		return ERROR_INVALID_DATA;

	assert(PathLength == 0);             /* MS-RDPESP 2.2.2.2 */
#ifndef _WIN32
	/* Windows 2012 server sends on a first call :
	 *     DesiredAccess     = 0x00100080: SYNCHRONIZE | FILE_READ_ATTRIBUTES
	 *     SharedAccess      = 0x00000007: FILE_SHARE_DELETE | FILE_SHARE_WRITE | FILE_SHARE_READ
	 *     CreateDisposition = 0x00000001: CREATE_NEW
	 *
	 * then Windows 2012 sends :
	 *     DesiredAccess     = 0x00120089: SYNCHRONIZE | READ_CONTROL | FILE_READ_ATTRIBUTES |
	 * FILE_READ_EA | FILE_READ_DATA SharedAccess      = 0x00000007: FILE_SHARE_DELETE |
	 * FILE_SHARE_WRITE | FILE_SHARE_READ CreateDisposition = 0x00000001: CREATE_NEW
	 *
	 * assert(DesiredAccess == (GENERIC_READ | GENERIC_WRITE));
	 * assert(SharedAccess == 0);
	 * assert(CreateDisposition == OPEN_EXISTING);
	 *
	 */
	WLog_Print(serial->log, WLOG_DEBUG,
	           "DesiredAccess: 0x%" PRIX32 ", SharedAccess: 0x%" PRIX32
	           ", CreateDisposition: 0x%" PRIX32 "",
	           DesiredAccess, SharedAccess, CreateDisposition);
	/* FIXME: As of today only the flags below are supported by CommCreateFileA: */
	DesiredAccess = GENERIC_READ | GENERIC_WRITE;
	SharedAccess = 0;
	CreateDisposition = OPEN_EXISTING;
#endif
	serial->hComm =
	    CreateFile(serial->device.name, DesiredAccess, SharedAccess, NULL, /* SecurityAttributes */
	               CreateDisposition, 0,                                   /* FlagsAndAttributes */
	               NULL);                                                  /* TemplateFile */

	if (!serial->hComm || (serial->hComm == INVALID_HANDLE_VALUE))
	{
		WLog_Print(serial->log, WLOG_WARN, "CreateFile failure: %s last-error: 0x%08" PRIX32 "",
		           serial->device.name, GetLastError());
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		goto error_handle;
	}

	_comm_setServerSerialDriver(serial->hComm, serial->ServerSerialDriverId);
	_comm_set_permissive(serial->hComm, serial->permissive);
	/* NOTE: binary mode/raw mode required for the redirection. On
	 * Linux, CommCreateFileA forces this setting.
	 */
	/* ZeroMemory(&dcb, sizeof(DCB)); */
	/* dcb.DCBlength = sizeof(DCB); */
	/* GetCommState(serial->hComm, &dcb); */
	/* dcb.fBinary = TRUE; */
	/* SetCommState(serial->hComm, &dcb); */
	assert(irp->FileId == 0);
	irp->FileId = irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */
	irp->IoStatus = STATUS_SUCCESS;
	WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %" PRIu32 ", FileId: %" PRIu32 ") created.",
	           serial->device.name, irp->device->id, irp->FileId);
error_handle:
	Stream_Write_UINT32(irp->output, irp->FileId); /* FileId (4 bytes) */
	Stream_Write_UINT8(irp->output, 0);            /* Information (1 byte) */
	return CHANNEL_RC_OK;
}

Project: FreeRDP

static BOOL rdg_process_tunnel_authorization_response(rdpRdg* rdg, wStream* s)
{
	UINT32 errorCode;
	UINT16 fieldsPresent;
	const char* error;
	WLog_DBG(TAG, "Tunnel authorization received");

	if (rdg->state != RDG_CLIENT_STATE_TUNNEL_AUTHORIZE)
	{
		return FALSE;
	}

	if (Stream_GetRemainingLength(s) < 8)
	{
		WLog_ERR(TAG, "[%s] Short packet %" PRIuz ", expected 8", __FUNCTION__,
		         Stream_GetRemainingLength(s));
		return FALSE;
	}

	Stream_Read_UINT32(s, errorCode);
	Stream_Read_UINT16(s, fieldsPresent);
	Stream_Seek_UINT16(s); /* reserved */
	error = rpc_error_to_string(errorCode);
	WLog_DBG(TAG, "errorCode=%s, fieldsPresent=%s", error,
	         tunnel_authorization_response_fields_present_to_string(fieldsPresent));

	if (FAILED(errorCode))
	{
		WLog_ERR(TAG, "Tunnel authorization error %s", error);
		freerdp_set_last_error_log(rdg->context, errorCode);
		return FALSE;
	}

	return rdg_send_channel_create(rdg);
}

Project: FreeRDP

static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char* method,
                                          const char* peerAddress, int timeout, BOOL* rpcFallback)
{
	HttpResponse* response = NULL;
	long statusCode;
	SSIZE_T bodyLength;
	long StatusCode;

	if (!rdg_tls_connect(rdg, tls, peerAddress, timeout))
		return FALSE;

	if (rdg->extAuth == HTTP_EXTENDED_AUTH_NONE)
	{
		if (!rdg_ntlm_init(rdg, tls))
			return FALSE;

		if (!rdg_send_http_request(rdg, tls, method, NULL))
			return FALSE;

		response = http_response_recv(tls, TRUE);

		if (!response)
			return FALSE;

		StatusCode = http_response_get_status_code(response);

		switch (StatusCode)
		{
			case HTTP_STATUS_NOT_FOUND:
			{
				WLog_INFO(TAG, "RD Gateway does not support HTTP transport.");

				if (rpcFallback)
					*rpcFallback = TRUE;

				http_response_free(response);
				return FALSE;
			}
			default:
				break;
		}

		if (!rdg_handle_ntlm_challenge(rdg->ntlm, response))
		{
			http_response_free(response);
			return FALSE;
		}

		http_response_free(response);
	}

	if (!rdg_send_http_request(rdg, tls, method, NULL))
		return FALSE;

	ntlm_free(rdg->ntlm);
	rdg->ntlm = NULL;
	response = http_response_recv(tls, TRUE);

	if (!response)
		return FALSE;

	statusCode = http_response_get_status_code(response);
	bodyLength = http_response_get_body_length(response);
	http_response_free(response);
	WLog_DBG(TAG, "%s authorization result: %d", method, statusCode);

	switch (statusCode)
	{
		case HTTP_STATUS_OK:
			break;
		case HTTP_STATUS_DENIED:
			freerdp_set_last_error_log(rdg->context, FREERDP_ERROR_CONNECT_ACCESS_DENIED);
			return FALSE;
		default:
			return FALSE;
	}

	if (strcmp(method, "RDG_OUT_DATA") == 0)
	{
		if (!rdg_skip_seed_payload(tls, bodyLength))
			return FALSE;
	}
	else
	{
		if (!rdg_send_http_request(rdg, tls, method, "chunked"))
			return FALSE;
	}

	return TRUE;
}

Project: FreeRDP

static UINT rdpei_recv_resume_touch_pdu(RDPEI_CHANNEL_CALLBACK* callback, wStream* s)
{
	RdpeiClientContext* rdpei = (RdpeiClientContext*)callback->plugin->pInterface;
	UINT error = CHANNEL_RC_OK;
	IFCALLRET(rdpei->ResumeTouch, error, rdpei);

	if (error)
		WLog_ERR(TAG, "rdpei->ResumeTouch failed with error %" PRIu32 "!", error);

	return error;
}

Project: FreeRDP

static int rdg_bio_read(BIO* bio, char* buf, int size)
{
	int status;
	rdpRdg* rdg = (rdpRdg*)BIO_get_data(bio);
	status = rdg_read_data_packet(rdg, (BYTE*)buf, size);

	if (status < 0)
	{
		BIO_clear_retry_flags(bio);
		return -1;
	}
	else if (status == 0)
	{
		BIO_set_retry_read(bio);
		WSASetLastError(WSAEWOULDBLOCK);
		return -1;
	}
	else
	{
		BIO_set_flags(bio, BIO_FLAGS_READ);
	}

	return status;
}

Project: FreeRDP

static void nego_attempt_tls(rdpNego* nego)
{
	nego->RequestedProtocols = PROTOCOL_SSL;
	WLog_DBG(TAG, "Attempting TLS security");

	if (!nego_transport_connect(nego))
	{
		nego->state = NEGO_STATE_FAIL;
		return;
	}

	if (!nego_send_negotiation_request(nego))
	{
		nego->state = NEGO_STATE_FAIL;
		return;
	}

	if (!nego_recv_response(nego))
	{
		nego->state = NEGO_STATE_FAIL;
		return;
	}

	if (nego->state != NEGO_STATE_FINAL)
	{
		nego_transport_disconnect(nego);

		if (nego->EnabledProtocols[PROTOCOL_RDP])
			nego->state = NEGO_STATE_RDP;
		else
			nego->state = NEGO_STATE_FAIL;
	}
}

Project: FreeRDP

static UINT serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
{
	UINT32 IoControlCode;
	UINT32 InputBufferLength;
	BYTE* InputBuffer = NULL;
	UINT32 OutputBufferLength;
	BYTE* OutputBuffer = NULL;
	DWORD BytesReturned = 0;

	if (Stream_GetRemainingLength(irp->input) < 32)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, OutputBufferLength); /* OutputBufferLength (4 bytes) */
	Stream_Read_UINT32(irp->input, InputBufferLength);  /* InputBufferLength (4 bytes) */
	Stream_Read_UINT32(irp->input, IoControlCode);      /* IoControlCode (4 bytes) */
	Stream_Seek(irp->input, 20);                        /* Padding (20 bytes) */

	if (Stream_GetRemainingLength(irp->input) < InputBufferLength)
		return ERROR_INVALID_DATA;

	OutputBuffer = (BYTE*)calloc(OutputBufferLength, sizeof(BYTE));

	if (OutputBuffer == NULL)
	{
		irp->IoStatus = STATUS_NO_MEMORY;
		goto error_handle;
	}

	InputBuffer = (BYTE*)calloc(InputBufferLength, sizeof(BYTE));

	if (InputBuffer == NULL)
	{
		irp->IoStatus = STATUS_NO_MEMORY;
		goto error_handle;
	}

	Stream_Read(irp->input, InputBuffer, InputBufferLength);
	WLog_Print(serial->log, WLOG_DEBUG,
	           "CommDeviceIoControl: CompletionId=%" PRIu32 ", IoControlCode=[0x%" PRIX32 "] %s",
	           irp->CompletionId, IoControlCode, _comm_serial_ioctl_name(IoControlCode));

	/* FIXME: CommDeviceIoControl to be replaced by DeviceIoControl() */
	if (CommDeviceIoControl(serial->hComm, IoControlCode, InputBuffer, InputBufferLength,
	                        OutputBuffer, OutputBufferLength, &BytesReturned, NULL))
	{
		/* WLog_Print(serial->log, WLOG_DEBUG, "CommDeviceIoControl: CompletionId=%"PRIu32",
		 * IoControlCode=[0x%"PRIX32"] %s done", irp->CompletionId, IoControlCode,
		 * _comm_serial_ioctl_name(IoControlCode)); */
		irp->IoStatus = STATUS_SUCCESS;
	}
	else
	{
		WLog_Print(serial->log, WLOG_DEBUG,
		           "CommDeviceIoControl failure: IoControlCode=[0x%" PRIX32
		           "] %s, last-error: 0x%08" PRIX32 "",
		           IoControlCode, _comm_serial_ioctl_name(IoControlCode), GetLastError());
		irp->IoStatus = _GetLastErrorToIoStatus(serial);
	}

error_handle:
	/* FIXME: find out whether it's required or not to get
	 * BytesReturned == OutputBufferLength when
	 * CommDeviceIoControl returns FALSE */
	assert(OutputBufferLength == BytesReturned);
	Stream_Write_UINT32(irp->output, BytesReturned); /* OutputBufferLength (4 bytes) */

	if (BytesReturned > 0)
	{
		if (!Stream_EnsureRemainingCapacity(irp->output, BytesReturned))
		{
			WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
			free(InputBuffer);
			free(OutputBuffer);
			return CHANNEL_RC_NO_MEMORY;
		}

		Stream_Write(irp->output, OutputBuffer, BytesReturned); /* OutputBuffer */
	}

	/* FIXME: Why at least Windows 2008R2 gets lost with this
	 * extra byte and likely on a IOCTL_SERIAL_SET_BAUD_RATE? The
	 * extra byte is well required according MS-RDPEFS
	 * 2.2.1.5.5 */
	/* else */
	/* { */
	/* 	Stream_Write_UINT8(irp->output, 0); /\* Padding (1 byte) *\/ */
	/* } */
	free(InputBuffer);
	free(OutputBuffer);
	return CHANNEL_RC_OK;
}

Project: FreeRDP

static BOOL printer_write_setting(const char* path, prn_conf_t type, const void* data,
                                  size_t length)
{
	DWORD written = 0;
	BOOL rc = FALSE;
	HANDLE file;
	size_t b64len;
	char* base64 = NULL;
	const char* name = filemap[type];
	char* abs = GetCombinedPath(path, name);

	if (!abs)
		return FALSE;

	file = CreateFileA(abs, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
	free(abs);

	if (file == INVALID_HANDLE_VALUE)
		return FALSE;

	if (length > 0)
	{
		base64 = crypto_base64_encode(data, length);

		if (!base64)
			goto fail;

		/* base64 char represents 6bit -> 4*(n/3) is the length which is
		 * always smaller than 2*n */
		b64len = strnlen(base64, 2 * length);
		rc = WriteFile(file, base64, b64len, &written, NULL);

		if (b64len != written)
			rc = FALSE;
	}
	else
		rc = TRUE;

fail:
	CloseHandle(file);
	free(base64);
	return rc;
}

Project: FreeRDP

static UINT serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
{
	UINT32 Length;
	UINT64 Offset;
	void* ptr;
	DWORD nbWritten = 0;

	if (Stream_GetRemainingLength(irp->input) < 32)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
	Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
	if (!Stream_SafeSeek(irp->input, 20))   /* Padding (20 bytes) */
		return ERROR_INVALID_DATA;

	/* MS-RDPESP 3.2.5.1.5: The Offset field is ignored
	 * assert(Offset == 0);
	 *
	 * Using a serial printer, noticed though this field could be
	 * set.
	 */
	WLog_Print(serial->log, WLOG_DEBUG, "writing %" PRIu32 " bytes to %s", Length,
	           serial->device.name);

	ptr = Stream_Pointer(irp->input);
	if (!Stream_SafeSeek(irp->input, Length))
		return ERROR_INVALID_DATA;
	/* FIXME: CommWriteFile to be replaced by WriteFile */
	if (CommWriteFile(serial->hComm, ptr, Length, &nbWritten, NULL))
	{
		irp->IoStatus = STATUS_SUCCESS;
	}
	else
	{
		WLog_Print(serial->log, WLOG_DEBUG,
		           "write failure to %s, nbWritten=%" PRIu32 ", last-error: 0x%08" PRIX32 "",
		           serial->device.name, nbWritten, GetLastError());
		irp->IoStatus = _GetLastErrorToIoStatus(serial);
	}

	WLog_Print(serial->log, WLOG_DEBUG, "%" PRIu32 " bytes written to %s", nbWritten,
	           serial->device.name);
	Stream_Write_UINT32(irp->output, nbWritten); /* Length (4 bytes) */
	Stream_Write_UINT8(irp->output, 0);          /* Padding (1 byte) */
	return CHANNEL_RC_OK;
}

Project: FreeRDP

BOOL nego_connect(rdpNego* nego)
{
	rdpSettings* settings = nego->transport->settings;

	if (nego->state == NEGO_STATE_INITIAL)
	{
		if (nego->EnabledProtocols[PROTOCOL_HYBRID_EX])
		{
			nego->state = NEGO_STATE_EXT;
		}
		else if (nego->EnabledProtocols[PROTOCOL_HYBRID])
		{
			nego->state = NEGO_STATE_NLA;
		}
		else if (nego->EnabledProtocols[PROTOCOL_SSL])
		{
			nego->state = NEGO_STATE_TLS;
		}
		else if (nego->EnabledProtocols[PROTOCOL_RDP])
		{
			nego->state = NEGO_STATE_RDP;
		}
		else
		{
			WLog_ERR(TAG, "No security protocol is enabled");
			nego->state = NEGO_STATE_FAIL;
			return FALSE;
		}

		if (!nego->NegotiateSecurityLayer)
		{
			WLog_DBG(TAG, "Security Layer Negotiation is disabled");
			/* attempt only the highest enabled protocol (see nego_attempt_*) */
			nego->EnabledProtocols[PROTOCOL_HYBRID] = FALSE;
			nego->EnabledProtocols[PROTOCOL_SSL] = FALSE;
			nego->EnabledProtocols[PROTOCOL_RDP] = FALSE;
			nego->EnabledProtocols[PROTOCOL_HYBRID_EX] = FALSE;

			if (nego->state == NEGO_STATE_EXT)
			{
				nego->EnabledProtocols[PROTOCOL_HYBRID_EX] = TRUE;
				nego->EnabledProtocols[PROTOCOL_HYBRID] = TRUE;
				nego->SelectedProtocol = PROTOCOL_HYBRID_EX;
			}
			else if (nego->state == NEGO_STATE_NLA)
			{
				nego->EnabledProtocols[PROTOCOL_HYBRID] = TRUE;
				nego->SelectedProtocol = PROTOCOL_HYBRID;
			}
			else if (nego->state == NEGO_STATE_TLS)
			{
				nego->EnabledProtocols[PROTOCOL_SSL] = TRUE;
				nego->SelectedProtocol = PROTOCOL_SSL;
			}
			else if (nego->state == NEGO_STATE_RDP)
			{
				nego->EnabledProtocols[PROTOCOL_RDP] = TRUE;
				nego->SelectedProtocol = PROTOCOL_RDP;
			}
		}

		if (nego->SendPreconnectionPdu)
		{
			if (!nego_send_preconnection_pdu(nego))
			{
				WLog_ERR(TAG, "Failed to send preconnection pdu");
				nego->state = NEGO_STATE_FINAL;
				return FALSE;
			}
		}
	}

	if (!nego->NegotiateSecurityLayer)
	{
		nego->state = NEGO_STATE_FINAL;
	}
	else
	{
		do
		{
			WLog_DBG(TAG, "state: %s", nego_state_string(nego->state));
			nego_send(nego);

			if (nego->state == NEGO_STATE_FAIL)
			{
				if (freerdp_get_last_error(nego->transport->context) == FREERDP_ERROR_SUCCESS)
					WLog_ERR(TAG, "Protocol Security Negotiation Failure");

				nego->state = NEGO_STATE_FINAL;
				return FALSE;
			}
		} while (nego->state != NEGO_STATE_FINAL);
	}

	WLog_DBG(TAG, "Negotiated %s security", protocol_security_string(nego->SelectedProtocol));
	/* update settings with negotiated protocol security */
	settings->RequestedProtocols = nego->RequestedProtocols;
	settings->SelectedProtocol = nego->SelectedProtocol;
	settings->NegotiationFlags = nego->flags;

	if (nego->SelectedProtocol == PROTOCOL_RDP)
	{
		settings->UseRdpSecurityLayer = TRUE;

		if (!settings->EncryptionMethods)
		{
			/**
			 * Advertise all supported encryption methods if the client
			 * implementation did not set any security methods
			 */
			settings->EncryptionMethods = ENCRYPTION_METHOD_40BIT | ENCRYPTION_METHOD_56BIT |
			                              ENCRYPTION_METHOD_128BIT | ENCRYPTION_METHOD_FIPS;
		}
	}

	/* finally connect security layer (if not already done) */
	if (!nego_security_connect(nego))
	{
		WLog_DBG(TAG, "Failed to connect with %s security",
		         protocol_security_string(nego->SelectedProtocol));
		return FALSE;
	}

	return TRUE;
}

Project: FreeRDP

void nego_free(rdpNego* nego)
{
	if (nego)
	{
		free(nego->RoutingToken);
		free(nego->cookie);
		free(nego);
	}
}

Project: FreeRDP

static int rdg_read_data_packet(rdpRdg* rdg, BYTE* buffer, int size)
{
	RdgPacketHeader header;
	size_t readCount = 0;
	int readSize;
	int status;

	if (!rdg->packetRemainingCount)
	{
		assert(sizeof(RdgPacketHeader) < INT_MAX);

		while (readCount < sizeof(RdgPacketHeader))
		{
			status = BIO_read(rdg->tlsOut->bio, (BYTE*)(&header) + readCount,
			                  (int)sizeof(RdgPacketHeader) - (int)readCount);

			if (status <= 0)
			{
				if (!BIO_should_retry(rdg->tlsOut->bio))
					return -1;

				if (!readCount)
					return 0;

				BIO_wait_read(rdg->tlsOut->bio, 50);
				continue;
			}

			readCount += (size_t)status;

			if (readCount > INT_MAX)
				return -1;
		}

		if (header.type != PKT_TYPE_DATA)
		{
			status = rdg_process_control_packet(rdg, header.type, header.packetLength);

			if (!status)
				return -1;

			return 0;
		}

		readCount = 0;

		while (readCount < 2)
		{
			status = BIO_read(rdg->tlsOut->bio, (BYTE*)(&rdg->packetRemainingCount) + readCount,
			                  2 - (int)readCount);

			if (status < 0)
			{
				if (!BIO_should_retry(rdg->tlsOut->bio))
					return -1;

				BIO_wait_read(rdg->tlsOut->bio, 50);
				continue;
			}

			readCount += (size_t)status;
		}
	}

	readSize = (rdg->packetRemainingCount < size ? rdg->packetRemainingCount : size);
	status = BIO_read(rdg->tlsOut->bio, buffer, readSize);

	if (status <= 0)
	{
		if (!BIO_should_retry(rdg->tlsOut->bio))
		{
			return -1;
		}

		return 0;
	}

	rdg->packetRemainingCount -= status;
	return status;
}

Project: FreeRDP

void nego_set_gateway_enabled(rdpNego* nego, BOOL GatewayEnabled)
{
	nego->GatewayEnabled = GatewayEnabled;
}

Project: FreeRDP

BOOL nego_process_negotiation_failure(rdpNego* nego, wStream* s)
{
	BYTE flags;
	UINT16 length;
	UINT32 failureCode;
	WLog_DBG(TAG, "RDP_NEG_FAILURE");
	if (Stream_GetRemainingLength(s) < 7)
		return FALSE;
	Stream_Read_UINT8(s, flags);
	Stream_Read_UINT16(s, length);
	Stream_Read_UINT32(s, failureCode);

	switch (failureCode)
	{
		case SSL_REQUIRED_BY_SERVER:
			WLog_WARN(TAG, "Error: SSL_REQUIRED_BY_SERVER");
			break;

		case SSL_NOT_ALLOWED_BY_SERVER:
			WLog_WARN(TAG, "Error: SSL_NOT_ALLOWED_BY_SERVER");
			nego->sendNegoData = TRUE;
			break;

		case SSL_CERT_NOT_ON_SERVER:
			WLog_ERR(TAG, "Error: SSL_CERT_NOT_ON_SERVER");
			nego->sendNegoData = TRUE;
			break;

		case INCONSISTENT_FLAGS:
			WLog_ERR(TAG, "Error: INCONSISTENT_FLAGS");
			break;

		case HYBRID_REQUIRED_BY_SERVER:
			WLog_WARN(TAG, "Error: HYBRID_REQUIRED_BY_SERVER");
			break;

		default:
			WLog_ERR(TAG, "Error: Unknown protocol security error %" PRIu32 "", failureCode);
			break;
	}

	nego->state = NEGO_STATE_FAIL;
	return TRUE;
}

Project: FreeRDP

static UINT rdpei_write_touch_frame(wStream* s, RDPINPUT_TOUCH_FRAME* frame)
{
	UINT32 index;
	int rectSize = 2;
	RDPINPUT_CONTACT_DATA* contact;
#ifdef WITH_DEBUG_RDPEI
	WLog_DBG(TAG, "contactCount: %" PRIu32 "", frame->contactCount);
	WLog_DBG(TAG, "frameOffset: 0x%016" PRIX64 "", frame->frameOffset);
#endif
	rdpei_write_2byte_unsigned(s,
	                           frame->contactCount); /* contactCount (TWO_BYTE_UNSIGNED_INTEGER) */
	/**
	 * the time offset from the previous frame (in microseconds).
	 * If this is the first frame being transmitted then this field MUST be set to zero.
	 */
	rdpei_write_8byte_unsigned(s, frame->frameOffset *
	                                  1000); /* frameOffset (EIGHT_BYTE_UNSIGNED_INTEGER) */

	if (!Stream_EnsureRemainingCapacity(s, (size_t)frame->contactCount * 64))
	{
		WLog_ERR(TAG, "Stream_EnsureRemainingCapacity failed!");
		return CHANNEL_RC_NO_MEMORY;
	}

	for (index = 0; index < frame->contactCount; index++)
	{
		contact = &frame->contacts[index];
		contact->fieldsPresent |= CONTACT_DATA_CONTACTRECT_PRESENT;
		contact->contactRectLeft = contact->x - rectSize;
		contact->contactRectTop = contact->y - rectSize;
		contact->contactRectRight = contact->x + rectSize;
		contact->contactRectBottom = contact->y + rectSize;
#ifdef WITH_DEBUG_RDPEI
		WLog_DBG(TAG, "contact[%" PRIu32 "].contactId: %" PRIu32 "", index, contact->contactId);
		WLog_DBG(TAG, "contact[%" PRIu32 "].fieldsPresent: %" PRIu32 "", index,
		         contact->fieldsPresent);
		WLog_DBG(TAG, "contact[%" PRIu32 "].x: %" PRId32 "", index, contact->x);
		WLog_DBG(TAG, "contact[%" PRIu32 "].y: %" PRId32 "", index, contact->y);
		WLog_DBG(TAG, "contact[%" PRIu32 "].contactFlags: 0x%08" PRIX32 "", index,
		         contact->contactFlags);
		rdpei_print_contact_flags(contact->contactFlags);
#endif
		Stream_Write_UINT8(s, contact->contactId); /* contactId (1 byte) */
		/* fieldsPresent (TWO_BYTE_UNSIGNED_INTEGER) */
		rdpei_write_2byte_unsigned(s, contact->fieldsPresent);
		rdpei_write_4byte_signed(s, contact->x); /* x (FOUR_BYTE_SIGNED_INTEGER) */
		rdpei_write_4byte_signed(s, contact->y); /* y (FOUR_BYTE_SIGNED_INTEGER) */
		/* contactFlags (FOUR_BYTE_UNSIGNED_INTEGER) */
		rdpei_write_4byte_unsigned(s, contact->contactFlags);

		if (contact->fieldsPresent & CONTACT_DATA_CONTACTRECT_PRESENT)
		{
			/* contactRectLeft (TWO_BYTE_SIGNED_INTEGER) */
			rdpei_write_2byte_signed(s, contact->contactRectLeft);
			/* contactRectTop (TWO_BYTE_SIGNED_INTEGER) */
			rdpei_write_2byte_signed(s, contact->contactRectTop);
			/* contactRectRight (TWO_BYTE_SIGNED_INTEGER) */
			rdpei_write_2byte_signed(s, contact->contactRectRight);
			/* contactRectBottom (TWO_BYTE_SIGNED_INTEGER) */
			rdpei_write_2byte_signed(s, contact->contactRectBottom);
		}

		if (contact->fieldsPresent & CONTACT_DATA_ORIENTATION_PRESENT)
		{
			/* orientation (FOUR_BYTE_UNSIGNED_INTEGER) */
			rdpei_write_4byte_unsigned(s, contact->orientation);
		}

		if (contact->fieldsPresent & CONTACT_DATA_PRESSURE_PRESENT)
		{
			/* pressure (FOUR_BYTE_UNSIGNED_INTEGER) */
			rdpei_write_4byte_unsigned(s, contact->pressure);
		}
	}

	return CHANNEL_RC_OK;
}

Project: FreeRDP

static UINT printer_free(DEVICE* device)
{
	IRP* irp;
	PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device;
	UINT error;
	SetEvent(printer_dev->stopEvent);

	if (WaitForSingleObject(printer_dev->thread, INFINITE) == WAIT_FAILED)
	{
		error = GetLastError();
		WLog_ERR(TAG, "WaitForSingleObject failed with error %" PRIu32 "", error);

		/* The analyzer is confused by this premature return value.
		 * Since this case can not be handled gracefully silence the
		 * analyzer here. */
#ifndef __clang_analyzer__
		return error;
#endif
	}

	while ((irp = (IRP*)InterlockedPopEntrySList(printer_dev->pIrpList)) != NULL)
		irp->Discard(irp);

	CloseHandle(printer_dev->thread);
	CloseHandle(printer_dev->stopEvent);
	CloseHandle(printer_dev->event);
	_aligned_free(printer_dev->pIrpList);

	if (printer_dev->printer)
		printer_dev->printer->ReleaseRef(printer_dev->printer);

	Stream_Free(printer_dev->device.data, TRUE);
	free(printer_dev);
	return CHANNEL_RC_OK;
}

Project: FreeRDP

BOOL nego_read_request(rdpNego* nego, wStream* s)
{
	BYTE li;
	BYTE type;
	UINT16 length;

	if (!tpkt_read_header(s, &length))
		return FALSE;

	if (!tpdu_read_connection_request(s, &li, length))
		return FALSE;

	if (li != Stream_GetRemainingLength(s) + 6)
	{
		WLog_ERR(TAG, "Incorrect TPDU length indicator.");
		return FALSE;
	}

	if (!nego_read_request_token_or_cookie(nego, s))
	{
		WLog_ERR(TAG, "Failed to parse routing token or cookie.");
		return FALSE;
	}

	if (Stream_GetRemainingLength(s) >= 8)
	{
		/* rdpNegData (optional) */
		Stream_Read_UINT8(s, type); /* Type */

		if (type != TYPE_RDP_NEG_REQ)
		{
			WLog_ERR(TAG, "Incorrect negotiation request type %" PRIu8 "", type);
			return FALSE;
		}

		if (!nego_process_negotiation_request(nego, s))
			return FALSE;
	}

	return tpkt_ensure_stream_consumed(s, length);
}

Project: FreeRDP

static BOOL nego_tcp_connect(rdpNego* nego)
{
	if (!nego->TcpConnected)
	{
		if (nego->GatewayEnabled)
		{
			if (nego->GatewayBypassLocal)
			{
				/* Attempt a direct connection first, and then fallback to using the gateway */
				WLog_INFO(TAG,
				          "Detecting if host can be reached locally. - This might take some time.");
				WLog_INFO(TAG, "To disable auto detection use /gateway-usage-method:direct");
				transport_set_gateway_enabled(nego->transport, FALSE);
				nego->TcpConnected =
				    transport_connect(nego->transport, nego->hostname, nego->port, 1);
			}

			if (!nego->TcpConnected)
			{
				transport_set_gateway_enabled(nego->transport, TRUE);
				nego->TcpConnected =
				    transport_connect(nego->transport, nego->hostname, nego->port, 15);
			}
		}
		else
		{
			nego->TcpConnected = transport_connect(nego->transport, nego->hostname, nego->port, 15);
		}
	}

	return nego->TcpConnected;
}

Project: FreeRDP

DWORD rdg_get_event_handles(rdpRdg* rdg, HANDLE* events, DWORD count)
{
	DWORD nCount = 0;
	assert(rdg != NULL);

	if (rdg->tlsOut && rdg->tlsOut->bio)
	{
		if (events && (nCount < count))
		{
			BIO_get_event(rdg->tlsOut->bio, &events[nCount]);
			nCount++;
		}
		else
			return 0;
	}

	if (rdg->tlsIn && rdg->tlsIn->bio)
	{
		if (events && (nCount < count))
		{
			BIO_get_event(rdg->tlsIn->bio, &events[nCount]);
			nCount++;
		}
		else
			return 0;
	}

	return nCount;
}

Project: FreeRDP

static BOOL rdg_send_handshake(rdpRdg* rdg)
{
	wStream* s;
	BOOL status;
	s = Stream_New(NULL, 14);

	if (!s)
		return FALSE;

	Stream_Write_UINT16(s, PKT_TYPE_HANDSHAKE_REQUEST); /* Type (2 bytes) */
	Stream_Write_UINT16(s, 0);                          /* Reserved (2 bytes) */
	Stream_Write_UINT32(s, 14);                         /* PacketLength (4 bytes) */
	Stream_Write_UINT8(s, 1);                           /* VersionMajor (1 byte) */
	Stream_Write_UINT8(s, 0);                           /* VersionMinor (1 byte) */
	Stream_Write_UINT16(s, 0);                          /* ClientVersion (2 bytes), must be 0 */
	Stream_Write_UINT16(s, rdg->extAuth);               /* ExtendedAuthentication (2 bytes) */
	Stream_SealLength(s);
	status = rdg_write_packet(rdg, s);
	Stream_Free(s, TRUE);

	if (status)
	{
		rdg->state = RDG_CLIENT_STATE_HANDSHAKE;
	}

	return status;
}

Project: FreeRDP

static const char* fields_present_to_string(UINT16 fieldsPresent, const t_err_mapping* map,
                                            size_t elements)
{
	size_t x = 0;
	static char buffer[1024] = { 0 };
	char fields[12];
	memset(buffer, 0, sizeof(buffer));

	for (x = 0; x < elements; x++)
	{
		if (buffer[0] != '\0')
			strcat(buffer, "|");

		if ((map[x].code & fieldsPresent) != 0)
			strcat(buffer, map[x].name);
	}

	sprintf_s(fields, ARRAYSIZE(fields), " [%04" PRIx16 "]", fieldsPresent);
	strcat(buffer, fields);
	return buffer;
}

Project: FreeRDP

static UINT rdpei_send_cs_ready_pdu(RDPEI_CHANNEL_CALLBACK* callback)
{
	UINT status;
	wStream* s;
	UINT32 flags;
	UINT32 pduLength;
	RDPEI_PLUGIN* rdpei = (RDPEI_PLUGIN*)callback->plugin;
	flags = 0;
	flags |= READY_FLAGS_SHOW_TOUCH_VISUALS;
	// flags |= READY_FLAGS_DISABLE_TIMESTAMP_INJECTION;
	pduLength = RDPINPUT_HEADER_LENGTH + 10;
	s = Stream_New(NULL, pduLength);

	if (!s)
	{
		WLog_ERR(TAG, "Stream_New failed!");
		return CHANNEL_RC_NO_MEMORY;
	}

	Stream_Seek(s, RDPINPUT_HEADER_LENGTH);
	Stream_Write_UINT32(s, flags);                   /* flags (4 bytes) */
	Stream_Write_UINT32(s, RDPINPUT_PROTOCOL_V10);   /* protocolVersion (4 bytes) */
	Stream_Write_UINT16(s, rdpei->maxTouchContacts); /* maxTouchContacts (2 bytes) */
	Stream_SealLength(s);
	status = rdpei_send_pdu(callback, s, EVENTID_CS_READY, pduLength);
	Stream_Free(s, TRUE);
	return status;
}

Project: FreeRDP

static UINT drive_process_irp_set_information(DRIVE_DEVICE* drive, IRP* irp)
{
	DRIVE_FILE* file;
	UINT32 FsInformationClass;
	UINT32 Length;

	if (!drive || !irp || !irp->Complete || !irp->input || !irp->output)
		return ERROR_INVALID_PARAMETER;

	if (Stream_GetRemainingLength(irp->input) < 32)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, FsInformationClass);
	Stream_Read_UINT32(irp->input, Length);
	Stream_Seek(irp->input, 24); /* Padding */
	file = drive_get_file_by_id(drive, irp->FileId);

	if (!file)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
	}
	else if (!drive_file_set_information(file, FsInformationClass, Length, irp->input))
	{
		irp->IoStatus = drive_map_windows_err(GetLastError());
	}

	if (file && file->is_dir && !PathIsDirectoryEmptyW(file->fullpath))
		irp->IoStatus = STATUS_DIRECTORY_NOT_EMPTY;

	Stream_Write_UINT32(irp->output, Length);
	return irp->Complete(irp);
}

Project: FreeRDP

BOOL nego_send_preconnection_pdu(rdpNego* nego)
{
	wStream* s;
	UINT32 cbSize;
	UINT16 cchPCB = 0;
	WCHAR* wszPCB = NULL;
	WLog_DBG(TAG, "Sending preconnection PDU");

	if (!nego_tcp_connect(nego))
		return FALSE;

	/* it's easier to always send the version 2 PDU, and it's just 2 bytes overhead */
	cbSize = PRECONNECTION_PDU_V2_MIN_SIZE;

	if (nego->PreconnectionBlob)
	{
		cchPCB = (UINT16)ConvertToUnicode(CP_UTF8, 0, nego->PreconnectionBlob, -1, &wszPCB, 0);
		cchPCB += 1; /* zero-termination */
		cbSize += cchPCB * 2;
	}

	s = Stream_New(NULL, cbSize);

	if (!s)
	{
		free(wszPCB);
		WLog_ERR(TAG, "Stream_New failed!");
		return FALSE;
	}

	Stream_Write_UINT32(s, cbSize);                /* cbSize */
	Stream_Write_UINT32(s, 0);                     /* Flags */
	Stream_Write_UINT32(s, PRECONNECTION_PDU_V2);  /* Version */
	Stream_Write_UINT32(s, nego->PreconnectionId); /* Id */
	Stream_Write_UINT16(s, cchPCB);                /* cchPCB */

	if (wszPCB)
	{
		Stream_Write(s, wszPCB, cchPCB * 2); /* wszPCB */
		free(wszPCB);
	}

	Stream_SealLength(s);

	if (transport_write(nego->transport, s) < 0)
	{
		Stream_Free(s, TRUE);
		return FALSE;
	}

	Stream_Free(s, TRUE);
	return TRUE;
}

Project: FreeRDP

static BOOL rdg_process_unknown_packet(rdpRdg* rdg, int type)
{
	WINPR_UNUSED(rdg);
	WINPR_UNUSED(type);
	WLog_WARN(TAG, "Unknown Control Packet received: %X", type);
	return TRUE;
}

Project: FreeRDP

static UINT printer_irp_request(DEVICE* device, IRP* irp)
{
	PRINTER_DEVICE* printer_dev = (PRINTER_DEVICE*)device;
	InterlockedPushEntrySList(printer_dev->pIrpList, &(irp->ItemEntry));
	SetEvent(printer_dev->event);
	return CHANNEL_RC_OK;
}

Project: FreeRDP

static BOOL printer_update_to_config(const rdpSettings* settings, const WCHAR* name, size_t length,
                                     const BYTE* data, size_t datalen)
{
	BOOL rc = FALSE;
	char* path = get_printer_config_path(settings, name, length);
	rc = printer_write_setting(path, PRN_CONF_DATA, data, datalen);
	free(path);
	return rc;
}

Project: FreeRDP

static UINT drive_process_irp_device_control(DRIVE_DEVICE* drive, IRP* irp)
{
	if (!drive || !irp)
		return ERROR_INVALID_PARAMETER;

	Stream_Write_UINT32(irp->output, 0); /* OutputBufferLength */
	return irp->Complete(irp);
}

Project: FreeRDP

static UINT drive_process_irp_close(DRIVE_DEVICE* drive, IRP* irp)
{
	void* key;
	DRIVE_FILE* file;

	if (!drive || !irp || !irp->Complete || !irp->output)
		return ERROR_INVALID_PARAMETER;

	file = drive_get_file_by_id(drive, irp->FileId);
	key = (void*)(size_t)irp->FileId;

	if (!file)
		irp->IoStatus = STATUS_UNSUCCESSFUL;
	else
	{
		ListDictionary_Remove(drive->files, key);

		if (drive_file_free(file))
			irp->IoStatus = STATUS_SUCCESS;
		else
			irp->IoStatus = drive_map_windows_err(GetLastError());
	}

	Stream_Zero(irp->output, 5); /* Padding(5) */
	return irp->Complete(irp);
}

Project: FreeRDP

static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp)
{
	const WCHAR* path;
	DRIVE_FILE* file;
	BYTE InitialQuery;
	UINT32 PathLength;
	UINT32 FsInformationClass;

	if (!drive || !irp || !irp->Complete)
		return ERROR_INVALID_PARAMETER;

	if (Stream_GetRemainingLength(irp->input) < 32)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, FsInformationClass);
	Stream_Read_UINT8(irp->input, InitialQuery);
	Stream_Read_UINT32(irp->input, PathLength);
	Stream_Seek(irp->input, 23); /* Padding */
	path = (WCHAR*)Stream_Pointer(irp->input);
	file = drive_get_file_by_id(drive, irp->FileId);

	if (file == NULL)
	{
		irp->IoStatus = STATUS_UNSUCCESSFUL;
		Stream_Write_UINT32(irp->output, 0); /* Length */
	}
	else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path, PathLength,
	                                     irp->output))
	{
		irp->IoStatus = drive_map_windows_err(GetLastError());
	}

	return irp->Complete(irp);
}

Project: FreeRDP

static void nego_attempt_rdp(rdpNego* nego)
{
	nego->RequestedProtocols = PROTOCOL_RDP;
	WLog_DBG(TAG, "Attempting RDP security");

	if (!nego_transport_connect(nego))
	{
		nego->state = NEGO_STATE_FAIL;
		return;
	}

	if (!nego_send_negotiation_request(nego))
	{
		nego->state = NEGO_STATE_FAIL;
		return;
	}

	if (!nego_recv_response(nego))
	{
		nego->state = NEGO_STATE_FAIL;
		return;
	}
}

Project: FreeRDP

static UINT drive_irp_request(DEVICE* device, IRP* irp)
{
	DRIVE_DEVICE* drive = (DRIVE_DEVICE*)device;

	if (!drive)
		return ERROR_INVALID_PARAMETER;

	if (!MessageQueue_Post(drive->IrpQueue, NULL, 0, (void*)irp, NULL))
	{
		WLog_ERR(TAG, "MessageQueue_Post failed!");
		return ERROR_INTERNAL_ERROR;
	}

	return CHANNEL_RC_OK;
}

Project: FreeRDP

static UINT drive_process_irp_silent_ignore(DRIVE_DEVICE* drive, IRP* irp)
{
	UINT32 FsInformationClass;

	if (!drive || !irp || !irp->output || !irp->Complete)
		return ERROR_INVALID_PARAMETER;

	if (Stream_GetRemainingLength(irp->input) < 4)
		return ERROR_INVALID_DATA;

	Stream_Read_UINT32(irp->input, FsInformationClass);
	Stream_Write_UINT32(irp->output, 0); /* Length */
	return irp->Complete(irp);
}

Project: FreeRDP

static wStream* rdg_build_http_request(rdpRdg* rdg, const char* method,
                                       const char* transferEncoding)
{
	wStream* s = NULL;
	HttpRequest* request = NULL;
	const char* uri;

	if (!rdg || !method)
		return NULL;

	uri = http_context_get_uri(rdg->http);
	request = http_request_new();

	if (!request)
		return NULL;

	if (!http_request_set_method(request, method) || !http_request_set_uri(request, uri))
		goto out;

	if (rdg->ntlm)
	{
		if (!rdg_set_ntlm_auth_header(rdg->ntlm, request))
			goto out;
	}

	if (transferEncoding)
	{
		http_request_set_transfer_encoding(request, transferEncoding);
	}

	s = http_request_write(rdg->http, request);
out:
	http_request_free(request);

	if (s)
		Stream_SealLength(s);

	return s;
}