1 /**
2  * FreeRDP: A Remote Desktop Protocol Implementation
3  * FreeRDP Core
4  *
5  * Copyright 2011 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6  * Copyright 2015 Thincast Technologies GmbH
7  * Copyright 2015 DI (FH) Martin Haimberger <martin.haimberger@thincast.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *     http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif
25 
26 #include "rdp.h"
27 #include "input.h"
28 #include "update.h"
29 #include "surface.h"
30 #include "transport.h"
31 #include "connection.h"
32 #include "message.h"
33 #include "buildflags.h"
34 #include "gateway/rpc_fault.h"
35 
36 #include <assert.h>
37 
38 #include <winpr/crt.h>
39 #include <winpr/string.h>
40 #include <winpr/stream.h>
41 #include <winpr/wtsapi.h>
42 #include <winpr/ssl.h>
43 #include <winpr/debug.h>
44 
45 #include <freerdp/freerdp.h>
46 #include <freerdp/error.h>
47 #include <freerdp/event.h>
48 #include <freerdp/locale/keyboard.h>
49 #include <freerdp/channels/channels.h>
50 #include <freerdp/version.h>
51 #include <freerdp/log.h>
52 #include <freerdp/cache/pointer.h>
53 
54 #include "settings.h"
55 
56 #define TAG FREERDP_TAG("core")
57 
58 /* connectErrorCode is 'extern' in error.h. See comment there.*/
59 
freerdp_channel_add_init_handle_data(rdpChannelHandles * handles,void * pInitHandle,void * pUserData)60 UINT freerdp_channel_add_init_handle_data(rdpChannelHandles* handles, void* pInitHandle,
61                                           void* pUserData)
62 {
63 	if (!handles->init)
64 		handles->init = ListDictionary_New(TRUE);
65 
66 	if (!handles->init)
67 	{
68 		WLog_ERR(TAG, "ListDictionary_New failed!");
69 		return ERROR_NOT_ENOUGH_MEMORY;
70 	}
71 
72 	if (!ListDictionary_Add(handles->init, pInitHandle, pUserData))
73 	{
74 		WLog_ERR(TAG, "ListDictionary_Add failed!");
75 		return ERROR_INTERNAL_ERROR;
76 	}
77 
78 	return CHANNEL_RC_OK;
79 }
80 
freerdp_channel_get_init_handle_data(rdpChannelHandles * handles,void * pInitHandle)81 void* freerdp_channel_get_init_handle_data(rdpChannelHandles* handles, void* pInitHandle)
82 {
83 	void* pUserData = NULL;
84 	pUserData = ListDictionary_GetItemValue(handles->init, pInitHandle);
85 	return pUserData;
86 }
87 
freerdp_channel_remove_init_handle_data(rdpChannelHandles * handles,void * pInitHandle)88 void freerdp_channel_remove_init_handle_data(rdpChannelHandles* handles, void* pInitHandle)
89 {
90 	ListDictionary_Remove(handles->init, pInitHandle);
91 
92 	if (ListDictionary_Count(handles->init) < 1)
93 	{
94 		ListDictionary_Free(handles->init);
95 		handles->init = NULL;
96 	}
97 }
98 
freerdp_channel_add_open_handle_data(rdpChannelHandles * handles,DWORD openHandle,void * pUserData)99 UINT freerdp_channel_add_open_handle_data(rdpChannelHandles* handles, DWORD openHandle,
100                                           void* pUserData)
101 {
102 	void* pOpenHandle = (void*)(size_t)openHandle;
103 
104 	if (!handles->open)
105 		handles->open = ListDictionary_New(TRUE);
106 
107 	if (!handles->open)
108 	{
109 		WLog_ERR(TAG, "ListDictionary_New failed!");
110 		return ERROR_NOT_ENOUGH_MEMORY;
111 	}
112 
113 	if (!ListDictionary_Add(handles->open, pOpenHandle, pUserData))
114 	{
115 		WLog_ERR(TAG, "ListDictionary_Add failed!");
116 		return ERROR_INTERNAL_ERROR;
117 	}
118 
119 	return CHANNEL_RC_OK;
120 }
121 
freerdp_channel_get_open_handle_data(rdpChannelHandles * handles,DWORD openHandle)122 void* freerdp_channel_get_open_handle_data(rdpChannelHandles* handles, DWORD openHandle)
123 {
124 	void* pUserData = NULL;
125 	void* pOpenHandle = (void*)(size_t)openHandle;
126 	pUserData = ListDictionary_GetItemValue(handles->open, pOpenHandle);
127 	return pUserData;
128 }
129 
freerdp_channel_remove_open_handle_data(rdpChannelHandles * handles,DWORD openHandle)130 void freerdp_channel_remove_open_handle_data(rdpChannelHandles* handles, DWORD openHandle)
131 {
132 	void* pOpenHandle = (void*)(size_t)openHandle;
133 	ListDictionary_Remove(handles->open, pOpenHandle);
134 
135 	if (ListDictionary_Count(handles->open) < 1)
136 	{
137 		ListDictionary_Free(handles->open);
138 		handles->open = NULL;
139 	}
140 }
141 
142 /** Creates a new connection based on the settings found in the "instance" parameter
143  *  It will use the callbacks registered on the structure to process the pre/post connect operations
144  *  that the caller requires.
145  *  @see struct rdp_freerdp in freerdp.h
146  *
147  *  @param instance - pointer to a rdp_freerdp structure that contains base information to establish
148  * the connection. On return, this function will be initialized with the new connection's settings.
149  *
150  *  @return TRUE if successful. FALSE otherwise.
151  *
152  */
freerdp_connect(freerdp * instance)153 BOOL freerdp_connect(freerdp* instance)
154 {
155 	UINT status2 = CHANNEL_RC_OK;
156 	rdpRdp* rdp;
157 	BOOL status = TRUE;
158 	rdpSettings* settings;
159 	ConnectionResultEventArgs e;
160 
161 	if (!instance)
162 		return FALSE;
163 
164 	/* We always set the return code to 0 before we start the connect sequence*/
165 	instance->ConnectionCallbackState = CLIENT_STATE_INITIAL;
166 #if !defined(DEFINE_NO_DEPRECATED)
167 	connectErrorCode = 0;
168 #endif
169 	freerdp_set_last_error_log(instance->context, FREERDP_ERROR_SUCCESS);
170 	clearChannelError(instance->context);
171 	ResetEvent(instance->context->abortEvent);
172 	rdp = instance->context->rdp;
173 	settings = instance->settings;
174 
175 	if (!freerdp_settings_set_default_order_support(settings))
176 		return FALSE;
177 
178 	IFCALLRET(instance->PreConnect, status, instance);
179 	instance->ConnectionCallbackState = CLIENT_STATE_PRECONNECT_PASSED;
180 
181 	if (status)
182 		status2 = freerdp_channels_pre_connect(instance->context->channels, instance);
183 
184 	if (settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002)
185 	{
186 		settings->KeyboardType = 7;
187 		settings->KeyboardSubType = 2;
188 		settings->KeyboardFunctionKey = 12;
189 	}
190 
191 	if (!status || (status2 != CHANNEL_RC_OK))
192 	{
193 		freerdp_set_last_error_if_not(instance->context, FREERDP_ERROR_PRE_CONNECT_FAILED);
194 
195 		WLog_ERR(TAG, "freerdp_pre_connect failed");
196 		goto freerdp_connect_finally;
197 	}
198 
199 	status = rdp_client_connect(rdp);
200 
201 	/* --authonly tests the connection without a UI */
202 	if (instance->settings->AuthenticationOnly)
203 	{
204 		WLog_ERR(TAG, "Authentication only, exit status %" PRId32 "", !status);
205 		goto freerdp_connect_finally;
206 	}
207 
208 	if (instance->settings->DumpRemoteFx)
209 	{
210 		instance->update->pcap_rfx = pcap_open(instance->settings->DumpRemoteFxFile, TRUE);
211 
212 		if (instance->update->pcap_rfx)
213 			instance->update->dump_rfx = TRUE;
214 	}
215 
216 	if (status)
217 	{
218 		pointer_cache_register_callbacks(instance->context->update);
219 		IFCALLRET(instance->PostConnect, status, instance);
220 		instance->ConnectionCallbackState = CLIENT_STATE_POSTCONNECT_PASSED;
221 
222 		if (status)
223 			status2 = freerdp_channels_post_connect(instance->context->channels, instance);
224 	}
225 	else
226 	{
227 		if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_CONNECT_TRANSPORT_FAILED)
228 			status = freerdp_reconnect(instance);
229 		else
230 			goto freerdp_connect_finally;
231 	}
232 
233 	if (!status || (status2 != CHANNEL_RC_OK) || !update_post_connect(instance->update))
234 	{
235 		WLog_ERR(TAG, "freerdp_post_connect failed");
236 
237 		freerdp_set_last_error_if_not(instance->context, FREERDP_ERROR_POST_CONNECT_FAILED);
238 
239 		status = FALSE;
240 		goto freerdp_connect_finally;
241 	}
242 
243 	if (instance->settings->PlayRemoteFx)
244 	{
245 		wStream* s;
246 		rdpUpdate* update;
247 		pcap_record record;
248 		update = instance->update;
249 		update->pcap_rfx = pcap_open(settings->PlayRemoteFxFile, FALSE);
250 		status = FALSE;
251 
252 		if (!update->pcap_rfx)
253 			goto freerdp_connect_finally;
254 		else
255 			update->play_rfx = TRUE;
256 
257 		status = TRUE;
258 
259 		while (pcap_has_next_record(update->pcap_rfx) && status)
260 		{
261 			pcap_get_next_record_header(update->pcap_rfx, &record);
262 
263 			if (!(s = StreamPool_Take(rdp->transport->ReceivePool, record.length)))
264 				break;
265 
266 			record.data = Stream_Buffer(s);
267 			pcap_get_next_record_content(update->pcap_rfx, &record);
268 			Stream_SetLength(s, record.length);
269 			Stream_SetPosition(s, 0);
270 
271 			if (!update_begin_paint(update))
272 				status = FALSE;
273 			else
274 			{
275 				if (update_recv_surfcmds(update, s) < 0)
276 					status = FALSE;
277 
278 				if (!update_end_paint(update))
279 					status = FALSE;
280 			}
281 
282 			Stream_Release(s);
283 		}
284 
285 		pcap_close(update->pcap_rfx);
286 		update->pcap_rfx = NULL;
287 		goto freerdp_connect_finally;
288 	}
289 
290 	if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES)
291 		freerdp_set_last_error_log(instance->context, FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);
292 
293 	SetEvent(rdp->transport->connectedEvent);
294 freerdp_connect_finally:
295 	EventArgsInit(&e, "freerdp");
296 	e.result = status ? 0 : -1;
297 	PubSub_OnConnectionResult(instance->context->pubSub, instance->context, &e);
298 
299 	if (!status)
300 		freerdp_disconnect(instance);
301 
302 	return status;
303 }
304 
freerdp_abort_connect(freerdp * instance)305 BOOL freerdp_abort_connect(freerdp* instance)
306 {
307 	if (!instance || !instance->context)
308 		return FALSE;
309 
310 	return SetEvent(instance->context->abortEvent);
311 }
312 
freerdp_get_fds(freerdp * instance,void ** rfds,int * rcount,void ** wfds,int * wcount)313 BOOL freerdp_get_fds(freerdp* instance, void** rfds, int* rcount, void** wfds, int* wcount)
314 {
315 	rdpRdp* rdp = instance->context->rdp;
316 	transport_get_fds(rdp->transport, rfds, rcount);
317 	return TRUE;
318 }
319 
freerdp_check_fds(freerdp * instance)320 BOOL freerdp_check_fds(freerdp* instance)
321 {
322 	int status;
323 	rdpRdp* rdp;
324 
325 	if (!instance)
326 		return FALSE;
327 
328 	if (!instance->context)
329 		return FALSE;
330 
331 	if (!instance->context->rdp)
332 		return FALSE;
333 
334 	rdp = instance->context->rdp;
335 	status = rdp_check_fds(rdp);
336 
337 	if (status < 0)
338 	{
339 		TerminateEventArgs e;
340 		rdpContext* context = instance->context;
341 		WLog_DBG(TAG, "rdp_check_fds() - %i", status);
342 		EventArgsInit(&e, "freerdp");
343 		e.code = 0;
344 		PubSub_OnTerminate(context->pubSub, context, &e);
345 		return FALSE;
346 	}
347 
348 	return TRUE;
349 }
350 
freerdp_get_event_handles(rdpContext * context,HANDLE * events,DWORD count)351 DWORD freerdp_get_event_handles(rdpContext* context, HANDLE* events, DWORD count)
352 {
353 	DWORD nCount = 0;
354 	nCount += transport_get_event_handles(context->rdp->transport, events, count);
355 
356 	if (nCount == 0)
357 		return 0;
358 
359 	if (events && (nCount < count + 2))
360 	{
361 		events[nCount++] = freerdp_channels_get_event_handle(context->instance);
362 		events[nCount++] = getChannelErrorEventHandle(context);
363 		events[nCount++] = context->abortEvent;
364 	}
365 	else
366 		return 0;
367 
368 	if (context->settings->AsyncInput)
369 	{
370 		if (nCount >= count)
371 			return 0;
372 
373 		events[nCount++] =
374 		    freerdp_get_message_queue_event_handle(context->instance, FREERDP_INPUT_MESSAGE_QUEUE);
375 	}
376 
377 	return nCount;
378 }
379 
freerdp_check_event_handles(rdpContext * context)380 BOOL freerdp_check_event_handles(rdpContext* context)
381 {
382 	BOOL status;
383 	status = freerdp_check_fds(context->instance);
384 
385 	if (!status)
386 	{
387 		if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
388 			WLog_ERR(TAG, "freerdp_check_fds() failed - %" PRIi32 "", status);
389 
390 		return FALSE;
391 	}
392 
393 	status = freerdp_channels_check_fds(context->channels, context->instance);
394 
395 	if (!status)
396 	{
397 		if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
398 			WLog_ERR(TAG, "freerdp_channels_check_fds() failed - %" PRIi32 "", status);
399 
400 		return FALSE;
401 	}
402 
403 	status = checkChannelErrorEvent(context);
404 
405 	if (!status)
406 	{
407 		if (freerdp_get_last_error(context) == FREERDP_ERROR_SUCCESS)
408 			WLog_ERR(TAG, "checkChannelErrorEvent() failed - %" PRIi32 "", status);
409 
410 		return FALSE;
411 	}
412 
413 	if (context->settings->AsyncInput)
414 	{
415 		int rc = freerdp_message_queue_process_pending_messages(context->instance,
416 		                                                        FREERDP_INPUT_MESSAGE_QUEUE);
417 
418 		if (rc < 0)
419 			return FALSE;
420 		else
421 			status = TRUE;
422 	}
423 
424 	return status;
425 }
426 
freerdp_get_message_queue(freerdp * instance,DWORD id)427 wMessageQueue* freerdp_get_message_queue(freerdp* instance, DWORD id)
428 {
429 	wMessageQueue* queue = NULL;
430 
431 	switch (id)
432 	{
433 		case FREERDP_UPDATE_MESSAGE_QUEUE:
434 			queue = instance->update->queue;
435 			break;
436 
437 		case FREERDP_INPUT_MESSAGE_QUEUE:
438 			queue = instance->input->queue;
439 			break;
440 	}
441 
442 	return queue;
443 }
444 
freerdp_get_message_queue_event_handle(freerdp * instance,DWORD id)445 HANDLE freerdp_get_message_queue_event_handle(freerdp* instance, DWORD id)
446 {
447 	HANDLE event = NULL;
448 	wMessageQueue* queue = NULL;
449 	queue = freerdp_get_message_queue(instance, id);
450 
451 	if (queue)
452 		event = MessageQueue_Event(queue);
453 
454 	return event;
455 }
456 
freerdp_message_queue_process_message(freerdp * instance,DWORD id,wMessage * message)457 int freerdp_message_queue_process_message(freerdp* instance, DWORD id, wMessage* message)
458 {
459 	int status = -1;
460 
461 	switch (id)
462 	{
463 		case FREERDP_UPDATE_MESSAGE_QUEUE:
464 			status = update_message_queue_process_message(instance->update, message);
465 			break;
466 
467 		case FREERDP_INPUT_MESSAGE_QUEUE:
468 			status = input_message_queue_process_message(instance->input, message);
469 			break;
470 	}
471 
472 	return status;
473 }
474 
freerdp_message_queue_process_pending_messages(freerdp * instance,DWORD id)475 int freerdp_message_queue_process_pending_messages(freerdp* instance, DWORD id)
476 {
477 	int status = -1;
478 
479 	switch (id)
480 	{
481 		case FREERDP_UPDATE_MESSAGE_QUEUE:
482 			status = update_message_queue_process_pending_messages(instance->update);
483 			break;
484 
485 		case FREERDP_INPUT_MESSAGE_QUEUE:
486 			status = input_message_queue_process_pending_messages(instance->input);
487 			break;
488 	}
489 
490 	return status;
491 }
492 
freerdp_send_channel_data(freerdp * instance,UINT16 channelId,const BYTE * data,size_t size)493 static BOOL freerdp_send_channel_data(freerdp* instance, UINT16 channelId, const BYTE* data,
494                                       size_t size)
495 {
496 	return rdp_send_channel_data(instance->context->rdp, channelId, data, size);
497 }
498 
freerdp_disconnect(freerdp * instance)499 BOOL freerdp_disconnect(freerdp* instance)
500 {
501 	BOOL rc = TRUE;
502 	rdpRdp* rdp;
503 
504 	if (!instance || !instance->context || !instance->context->rdp)
505 		return FALSE;
506 
507 	rdp = instance->context->rdp;
508 
509 	if (!rdp_client_disconnect(rdp))
510 		rc = FALSE;
511 
512 	update_post_disconnect(instance->update);
513 
514 	if (instance->settings->AsyncInput)
515 	{
516 		wMessageQueue* inputQueue =
517 		    freerdp_get_message_queue(instance, FREERDP_INPUT_MESSAGE_QUEUE);
518 		MessageQueue_PostQuit(inputQueue, 0);
519 	}
520 
521 	IFCALL(instance->PostDisconnect, instance);
522 
523 	if (instance->update->pcap_rfx)
524 	{
525 		instance->update->dump_rfx = FALSE;
526 		pcap_close(instance->update->pcap_rfx);
527 		instance->update->pcap_rfx = NULL;
528 	}
529 
530 	freerdp_channels_close(instance->context->channels, instance);
531 	return rc;
532 }
533 
freerdp_disconnect_before_reconnect(freerdp * instance)534 BOOL freerdp_disconnect_before_reconnect(freerdp* instance)
535 {
536 	rdpRdp* rdp = instance->context->rdp;
537 	return rdp_client_disconnect_and_clear(rdp);
538 }
539 
freerdp_reconnect(freerdp * instance)540 BOOL freerdp_reconnect(freerdp* instance)
541 {
542 	BOOL status;
543 	rdpRdp* rdp = instance->context->rdp;
544 	ResetEvent(instance->context->abortEvent);
545 	status = rdp_client_reconnect(rdp);
546 	return status;
547 }
548 
freerdp_shall_disconnect(freerdp * instance)549 BOOL freerdp_shall_disconnect(freerdp* instance)
550 {
551 	if (!instance || !instance->context)
552 		return FALSE;
553 
554 	if (WaitForSingleObject(instance->context->abortEvent, 0) != WAIT_OBJECT_0)
555 		return FALSE;
556 
557 	return TRUE;
558 }
559 
freerdp_focus_required(freerdp * instance)560 BOOL freerdp_focus_required(freerdp* instance)
561 {
562 	rdpRdp* rdp;
563 	BOOL bRetCode = FALSE;
564 	rdp = instance->context->rdp;
565 
566 	if (rdp->resendFocus)
567 	{
568 		bRetCode = TRUE;
569 		rdp->resendFocus = FALSE;
570 	}
571 
572 	return bRetCode;
573 }
574 
freerdp_set_focus(freerdp * instance)575 void freerdp_set_focus(freerdp* instance)
576 {
577 	rdpRdp* rdp;
578 	rdp = instance->context->rdp;
579 	rdp->resendFocus = TRUE;
580 }
581 
freerdp_get_version(int * major,int * minor,int * revision)582 void freerdp_get_version(int* major, int* minor, int* revision)
583 {
584 	if (major != NULL)
585 		*major = FREERDP_VERSION_MAJOR;
586 
587 	if (minor != NULL)
588 		*minor = FREERDP_VERSION_MINOR;
589 
590 	if (revision != NULL)
591 		*revision = FREERDP_VERSION_REVISION;
592 }
593 
freerdp_get_version_string(void)594 const char* freerdp_get_version_string(void)
595 {
596 	return FREERDP_VERSION_FULL;
597 }
598 
freerdp_get_build_date(void)599 const char* freerdp_get_build_date(void)
600 {
601 	static char build_date[] = __DATE__ " " __TIME__;
602 	return build_date;
603 }
604 
freerdp_get_build_config(void)605 const char* freerdp_get_build_config(void)
606 {
607 	static const char build_config[] =
608 	    "Build configuration: " BUILD_CONFIG "\n"
609 	    "Build type:          " BUILD_TYPE "\n"
610 	    "CFLAGS:              " CFLAGS "\n"
611 	    "Compiler:            " COMPILER_ID ", " COMPILER_VERSION "\n"
612 	    "Target architecture: " TARGET_ARCH "\n";
613 	return build_config;
614 }
615 
freerdp_get_build_revision(void)616 const char* freerdp_get_build_revision(void)
617 {
618 	return GIT_REVISION;
619 }
620 
621 static wEventType FreeRDP_Events[] = {
622 	DEFINE_EVENT_ENTRY(WindowStateChange) DEFINE_EVENT_ENTRY(ResizeWindow)
623 	    DEFINE_EVENT_ENTRY(LocalResizeWindow) DEFINE_EVENT_ENTRY(EmbedWindow)
624 	        DEFINE_EVENT_ENTRY(PanningChange) DEFINE_EVENT_ENTRY(ZoomingChange)
625 	            DEFINE_EVENT_ENTRY(ErrorInfo) DEFINE_EVENT_ENTRY(Terminate)
626 	                DEFINE_EVENT_ENTRY(ConnectionResult) DEFINE_EVENT_ENTRY(ChannelConnected)
627 	                    DEFINE_EVENT_ENTRY(ChannelDisconnected) DEFINE_EVENT_ENTRY(MouseEvent)
628 	                        DEFINE_EVENT_ENTRY(Activated) DEFINE_EVENT_ENTRY(Timer)
629 	                            DEFINE_EVENT_ENTRY(GraphicsReset)
630 };
631 
632 /** Allocator function for a rdp context.
633  *  The function will allocate a rdpRdp structure using rdp_new(), then copy
634  *  its contents to the appropriate fields in the rdp_freerdp structure given in parameters.
635  *  It will also initialize the 'context' field in the rdp_freerdp structure as needed.
636  *  If the caller has set the ContextNew callback in the 'instance' parameter, it will be called at
637  * the end of the function.
638  *
639  *  @param instance - Pointer to the rdp_freerdp structure that will be initialized with the new
640  * context.
641  */
freerdp_context_new(freerdp * instance)642 BOOL freerdp_context_new(freerdp* instance)
643 {
644 	rdpRdp* rdp;
645 	rdpContext* context;
646 	BOOL ret = TRUE;
647 	instance->context = (rdpContext*)calloc(1, instance->ContextSize);
648 
649 	if (!instance->context)
650 		return FALSE;
651 
652 	context = instance->context;
653 	context->instance = instance;
654 	context->ServerMode = FALSE;
655 	context->settings = instance->settings;
656 	context->disconnectUltimatum = 0;
657 	context->pubSub = PubSub_New(TRUE);
658 
659 	if (!context->pubSub)
660 		goto fail;
661 
662 	PubSub_AddEventTypes(context->pubSub, FreeRDP_Events, ARRAYSIZE(FreeRDP_Events));
663 	context->metrics = metrics_new(context);
664 
665 	if (!context->metrics)
666 		goto fail;
667 
668 	rdp = rdp_new(context);
669 
670 	if (!rdp)
671 		goto fail;
672 
673 	instance->input = rdp->input;
674 	instance->update = rdp->update;
675 	instance->settings = rdp->settings;
676 	instance->autodetect = rdp->autodetect;
677 	instance->heartbeat = rdp->heartbeat;
678 	context->graphics = graphics_new(context);
679 
680 	if (!context->graphics)
681 		goto fail;
682 
683 	context->rdp = rdp;
684 	context->input = instance->input;
685 	context->update = instance->update;
686 	context->settings = instance->settings;
687 	context->autodetect = instance->autodetect;
688 	instance->update->context = instance->context;
689 	instance->update->pointer->context = instance->context;
690 	instance->update->primary->context = instance->context;
691 	instance->update->secondary->context = instance->context;
692 	instance->update->altsec->context = instance->context;
693 	instance->input->context = context;
694 	instance->autodetect->context = context;
695 
696 	if (!(context->errorDescription = calloc(1, 500)))
697 	{
698 		WLog_ERR(TAG, "calloc failed!");
699 		goto fail;
700 	}
701 
702 	if (!(context->channelErrorEvent = CreateEvent(NULL, TRUE, FALSE, NULL)))
703 	{
704 		WLog_ERR(TAG, "CreateEvent failed!");
705 		goto fail;
706 	}
707 
708 	update_register_client_callbacks(rdp->update);
709 	instance->context->abortEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
710 
711 	if (!instance->context->abortEvent)
712 		goto fail;
713 
714 	if (!(context->channels = freerdp_channels_new(instance)))
715 		goto fail;
716 
717 	IFCALLRET(instance->ContextNew, ret, instance, instance->context);
718 
719 	if (ret)
720 		return TRUE;
721 
722 fail:
723 	freerdp_context_free(instance);
724 	return FALSE;
725 }
726 
727 /** Deallocator function for a rdp context.
728  *  The function will deallocate the resources from the 'instance' parameter that were allocated
729  * from a call to freerdp_context_new(). If the ContextFree callback is set in the 'instance'
730  * parameter, it will be called before deallocation occurs.
731  *
732  *  @param instance - Pointer to the rdp_freerdp structure that was initialized by a call to
733  * freerdp_context_new(). On return, the fields associated to the context are invalid.
734  */
freerdp_context_free(freerdp * instance)735 void freerdp_context_free(freerdp* instance)
736 {
737 	if (!instance)
738 		return;
739 
740 	if (!instance->context)
741 		return;
742 
743 	IFCALL(instance->ContextFree, instance, instance->context);
744 	rdp_free(instance->context->rdp);
745 	instance->context->rdp = NULL;
746 	graphics_free(instance->context->graphics);
747 	instance->context->graphics = NULL;
748 	PubSub_Free(instance->context->pubSub);
749 	metrics_free(instance->context->metrics);
750 	CloseHandle(instance->context->channelErrorEvent);
751 	free(instance->context->errorDescription);
752 	CloseHandle(instance->context->abortEvent);
753 	instance->context->abortEvent = NULL;
754 	freerdp_channels_free(instance->context->channels);
755 	free(instance->context);
756 	instance->context = NULL;
757 }
758 
freerdp_get_disconnect_ultimatum(rdpContext * context)759 int freerdp_get_disconnect_ultimatum(rdpContext* context)
760 {
761 	return context->disconnectUltimatum;
762 }
763 
freerdp_error_info(freerdp * instance)764 UINT32 freerdp_error_info(freerdp* instance)
765 {
766 	return instance->context->rdp->errorInfo;
767 }
768 
freerdp_set_error_info(rdpRdp * rdp,UINT32 error)769 void freerdp_set_error_info(rdpRdp* rdp, UINT32 error)
770 {
771 	if (!rdp)
772 		return;
773 
774 	rdp_set_error_info(rdp, error);
775 }
776 
freerdp_send_error_info(rdpRdp * rdp)777 BOOL freerdp_send_error_info(rdpRdp* rdp)
778 {
779 	if (!rdp)
780 		return FALSE;
781 
782 	return rdp_send_error_info(rdp);
783 }
784 
freerdp_get_last_error(rdpContext * context)785 UINT32 freerdp_get_last_error(rdpContext* context)
786 {
787 	return context->LastError;
788 }
789 
freerdp_get_last_error_name(UINT32 code)790 const char* freerdp_get_last_error_name(UINT32 code)
791 {
792 	const char* name = NULL;
793 	const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
794 	const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
795 
796 	switch (cls)
797 	{
798 		case FREERDP_ERROR_ERRBASE_CLASS:
799 			name = freerdp_get_error_base_name(type);
800 			break;
801 
802 		case FREERDP_ERROR_ERRINFO_CLASS:
803 			name = freerdp_get_error_info_name(type);
804 			break;
805 
806 		case FREERDP_ERROR_CONNECT_CLASS:
807 			name = freerdp_get_error_connect_name(type);
808 			break;
809 
810 		default:
811 			name = rpc_error_to_string(code);
812 			break;
813 	}
814 
815 	return name;
816 }
817 
freerdp_get_last_error_string(UINT32 code)818 const char* freerdp_get_last_error_string(UINT32 code)
819 {
820 	const char* string = NULL;
821 	const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
822 	const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
823 
824 	switch (cls)
825 	{
826 		case FREERDP_ERROR_ERRBASE_CLASS:
827 			string = freerdp_get_error_base_string(type);
828 			break;
829 
830 		case FREERDP_ERROR_ERRINFO_CLASS:
831 			string = freerdp_get_error_info_string(type);
832 			break;
833 
834 		case FREERDP_ERROR_CONNECT_CLASS:
835 			string = freerdp_get_error_connect_string(type);
836 			break;
837 
838 		default:
839 			string = rpc_error_to_string(code);
840 			break;
841 	}
842 
843 	return string;
844 }
845 
freerdp_get_last_error_category(UINT32 code)846 const char* freerdp_get_last_error_category(UINT32 code)
847 {
848 	const char* string = NULL;
849 	const UINT32 cls = GET_FREERDP_ERROR_CLASS(code);
850 	const UINT32 type = GET_FREERDP_ERROR_TYPE(code);
851 
852 	switch (cls)
853 	{
854 		case FREERDP_ERROR_ERRBASE_CLASS:
855 			string = freerdp_get_error_base_category(type);
856 			break;
857 
858 		case FREERDP_ERROR_ERRINFO_CLASS:
859 			string = freerdp_get_error_info_category(type);
860 			break;
861 
862 		case FREERDP_ERROR_CONNECT_CLASS:
863 			string = freerdp_get_error_connect_category(type);
864 			break;
865 
866 		default:
867 			string = rpc_error_to_category(code);
868 			break;
869 	}
870 
871 	return string;
872 }
873 
freerdp_set_last_error(rdpContext * context,UINT32 lastError)874 void freerdp_set_last_error(rdpContext* context, UINT32 lastError)
875 {
876 	freerdp_set_last_error_ex(context, lastError, NULL, NULL, -1);
877 }
878 
freerdp_set_last_error_ex(rdpContext * context,UINT32 lastError,const char * fkt,const char * file,int line)879 void freerdp_set_last_error_ex(rdpContext* context, UINT32 lastError, const char* fkt,
880                                const char* file, int line)
881 {
882 	if (lastError)
883 		WLog_ERR(TAG, "%s:%s %s [0x%08" PRIX32 "]", fkt, __FUNCTION__,
884 		         freerdp_get_last_error_name(lastError), lastError);
885 
886 	if (lastError == FREERDP_ERROR_SUCCESS)
887 	{
888 		WLog_INFO(TAG, "%s:%s resetting error state", fkt, __FUNCTION__);
889 	}
890 	else if (context->LastError != FREERDP_ERROR_SUCCESS)
891 	{
892 		WLog_ERR(TAG, "%s: TODO: Trying to set error code %s, but %s already set!", fkt,
893 		         freerdp_get_last_error_name(lastError),
894 		         freerdp_get_last_error_name(context->LastError));
895 	}
896 
897 	context->LastError = lastError;
898 
899 #if !defined(DEFINE_NO_DEPRECATED)
900 	switch (lastError)
901 	{
902 		case FREERDP_ERROR_PRE_CONNECT_FAILED:
903 			connectErrorCode = PREECONNECTERROR;
904 			break;
905 
906 		case FREERDP_ERROR_CONNECT_UNDEFINED:
907 			connectErrorCode = UNDEFINEDCONNECTERROR;
908 			break;
909 
910 		case FREERDP_ERROR_POST_CONNECT_FAILED:
911 			connectErrorCode = POSTCONNECTERROR;
912 			break;
913 
914 		case FREERDP_ERROR_DNS_ERROR:
915 			connectErrorCode = DNSERROR;
916 			break;
917 
918 		case FREERDP_ERROR_DNS_NAME_NOT_FOUND:
919 			connectErrorCode = DNSNAMENOTFOUND;
920 			break;
921 
922 		case FREERDP_ERROR_CONNECT_FAILED:
923 			connectErrorCode = CONNECTERROR;
924 			break;
925 
926 		case FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR:
927 			connectErrorCode = MCSCONNECTINITIALERROR;
928 			break;
929 
930 		case FREERDP_ERROR_TLS_CONNECT_FAILED:
931 			connectErrorCode = TLSCONNECTERROR;
932 			break;
933 
934 		case FREERDP_ERROR_AUTHENTICATION_FAILED:
935 			connectErrorCode = AUTHENTICATIONERROR;
936 			break;
937 
938 		case FREERDP_ERROR_INSUFFICIENT_PRIVILEGES:
939 			connectErrorCode = INSUFFICIENTPRIVILEGESERROR;
940 			break;
941 
942 		case FREERDP_ERROR_CONNECT_CANCELLED:
943 			connectErrorCode = CANCELEDBYUSER;
944 			break;
945 
946 		case FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED:
947 			connectErrorCode = CONNECTERROR;
948 			break;
949 
950 		case FREERDP_ERROR_CONNECT_TRANSPORT_FAILED:
951 			connectErrorCode = CONNECTERROR;
952 			break;
953 	}
954 #endif
955 }
956 
freerdp_get_logon_error_info_type(UINT32 type)957 const char* freerdp_get_logon_error_info_type(UINT32 type)
958 {
959 	switch (type)
960 	{
961 		case LOGON_MSG_DISCONNECT_REFUSED:
962 			return "LOGON_MSG_DISCONNECT_REFUSED";
963 
964 		case LOGON_MSG_NO_PERMISSION:
965 			return "LOGON_MSG_NO_PERMISSION";
966 
967 		case LOGON_MSG_BUMP_OPTIONS:
968 			return "LOGON_MSG_BUMP_OPTIONS";
969 
970 		case LOGON_MSG_RECONNECT_OPTIONS:
971 			return "LOGON_MSG_RECONNECT_OPTIONS";
972 
973 		case LOGON_MSG_SESSION_TERMINATE:
974 			return "LOGON_MSG_SESSION_TERMINATE";
975 
976 		case LOGON_MSG_SESSION_CONTINUE:
977 			return "LOGON_MSG_SESSION_CONTINUE";
978 
979 		default:
980 			return "UNKNOWN";
981 	}
982 }
983 
freerdp_get_logon_error_info_data(UINT32 data)984 const char* freerdp_get_logon_error_info_data(UINT32 data)
985 {
986 	switch (data)
987 	{
988 		case LOGON_FAILED_BAD_PASSWORD:
989 			return "LOGON_FAILED_BAD_PASSWORD";
990 
991 		case LOGON_FAILED_UPDATE_PASSWORD:
992 			return "LOGON_FAILED_UPDATE_PASSWORD";
993 
994 		case LOGON_FAILED_OTHER:
995 			return "LOGON_FAILED_OTHER";
996 
997 		case LOGON_WARNING:
998 			return "LOGON_WARNING";
999 
1000 		default:
1001 			return "SESSION_ID";
1002 	}
1003 }
1004 
1005 /** Allocator function for the rdp_freerdp structure.
1006  *  @return an allocated structure filled with 0s. Need to be deallocated using freerdp_free()
1007  */
freerdp_new(void)1008 freerdp* freerdp_new(void)
1009 {
1010 	freerdp* instance;
1011 	instance = (freerdp*)calloc(1, sizeof(freerdp));
1012 
1013 	if (!instance)
1014 		return NULL;
1015 
1016 	instance->ContextSize = sizeof(rdpContext);
1017 	instance->SendChannelData = freerdp_send_channel_data;
1018 	instance->ReceiveChannelData = freerdp_channels_data;
1019 	return instance;
1020 }
1021 
1022 /** Deallocator function for the rdp_freerdp structure.
1023  *  @param instance - pointer to the rdp_freerdp structure to deallocate.
1024  *                    On return, this pointer is not valid anymore.
1025  */
freerdp_free(freerdp * instance)1026 void freerdp_free(freerdp* instance)
1027 {
1028 	free(instance);
1029 }
1030 
freerdp_get_transport_sent(rdpContext * context,BOOL resetCount)1031 ULONG freerdp_get_transport_sent(rdpContext* context, BOOL resetCount)
1032 {
1033 	ULONG written = context->rdp->transport->written;
1034 
1035 	if (resetCount)
1036 		context->rdp->transport->written = 0;
1037 
1038 	return written;
1039 }
1040 
freerdp_nla_impersonate(rdpContext * context)1041 BOOL freerdp_nla_impersonate(rdpContext* context)
1042 {
1043 	rdpNla* nla;
1044 
1045 	if (!context)
1046 		return FALSE;
1047 
1048 	if (!context->rdp)
1049 		return FALSE;
1050 
1051 	if (!context->rdp->transport)
1052 		return FALSE;
1053 
1054 	nla = context->rdp->transport->nla;
1055 	return nla_impersonate(nla);
1056 }
1057 
freerdp_nla_revert_to_self(rdpContext * context)1058 BOOL freerdp_nla_revert_to_self(rdpContext* context)
1059 {
1060 	rdpNla* nla;
1061 
1062 	if (!context)
1063 		return FALSE;
1064 
1065 	if (!context->rdp)
1066 		return FALSE;
1067 
1068 	if (!context->rdp->transport)
1069 		return FALSE;
1070 
1071 	nla = context->rdp->transport->nla;
1072 	return nla_revert_to_self(nla);
1073 }
1074 
getChannelErrorEventHandle(rdpContext * context)1075 HANDLE getChannelErrorEventHandle(rdpContext* context)
1076 {
1077 	return context->channelErrorEvent;
1078 }
1079 
checkChannelErrorEvent(rdpContext * context)1080 BOOL checkChannelErrorEvent(rdpContext* context)
1081 {
1082 	if (WaitForSingleObject(context->channelErrorEvent, 0) == WAIT_OBJECT_0)
1083 	{
1084 		WLog_ERR(TAG, "%s. Error was %" PRIu32 "", context->errorDescription,
1085 		         context->channelErrorNum);
1086 		return FALSE;
1087 	}
1088 
1089 	return TRUE;
1090 }
1091 
1092 /**
1093  * Function description
1094  *
1095  * @return 0 on success, otherwise a Win32 error code
1096  */
getChannelError(rdpContext * context)1097 UINT getChannelError(rdpContext* context)
1098 {
1099 	return context->channelErrorNum;
1100 }
1101 
getChannelErrorDescription(rdpContext * context)1102 const char* getChannelErrorDescription(rdpContext* context)
1103 {
1104 	return context->errorDescription;
1105 }
1106 
clearChannelError(rdpContext * context)1107 void clearChannelError(rdpContext* context)
1108 {
1109 	context->channelErrorNum = 0;
1110 	memset(context->errorDescription, 0, 500);
1111 	ResetEvent(context->channelErrorEvent);
1112 }
1113 
setChannelError(rdpContext * context,UINT errorNum,char * description)1114 void setChannelError(rdpContext* context, UINT errorNum, char* description)
1115 {
1116 	context->channelErrorNum = errorNum;
1117 	strncpy(context->errorDescription, description, 499);
1118 	SetEvent(context->channelErrorEvent);
1119 }
1120 
freerdp_nego_get_routing_token(rdpContext * context,DWORD * length)1121 const char* freerdp_nego_get_routing_token(rdpContext* context, DWORD* length)
1122 {
1123 	if (!context || !context->rdp)
1124 		return NULL;
1125 
1126 	return (const char*)nego_get_routing_token(context->rdp->nego, length);
1127 }
1128