Ejemplo n.º 1
0
BOOL transport_connect_tls(rdpTransport* transport)
{
	rdpSettings* settings = transport->settings;
	rdpTls* targetTls;
	BIO* targetBio;
	int tls_status;
	freerdp* instance;
	rdpContext* context;
	instance = (freerdp*) transport->settings->instance;
	context = instance->context;

	if (transport->layer == TRANSPORT_LAYER_TSG)
	{
		transport->TsgTls = tls_new(transport->settings);
		transport->layer = TRANSPORT_LAYER_TSG_TLS;
		targetTls = transport->TsgTls;
		targetBio = transport->frontBio;
	}
	else
	{
		if (!transport->TlsIn)
			transport->TlsIn = tls_new(settings);

		if (!transport->TlsOut)
			transport->TlsOut = transport->TlsIn;

		targetTls = transport->TlsIn;
		targetBio = transport->TcpIn->bufferedBio;
		transport->layer = TRANSPORT_LAYER_TLS;
	}

	targetTls->hostname = settings->ServerHostname;
	targetTls->port = settings->ServerPort;

	if (targetTls->port == 0)
		targetTls->port = 3389;

	targetTls->isGatewayTransport = FALSE;
	tls_status = tls_connect(targetTls, targetBio);

	if (tls_status < 1)
	{
		if (tls_status < 0)
		{
			if (!connectErrorCode)
				connectErrorCode = TLSCONNECTERROR;

			if (!freerdp_get_last_error(context))
				freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
		}
		else
		{
			if (!freerdp_get_last_error(context))
				freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED);
		}

		return FALSE;
	}

	transport->frontBio = targetTls->bio;

	if (!transport->frontBio)
	{
		WLog_ERR(TAG, "unable to prepend a filtering TLS bio");
		return FALSE;
	}

	return TRUE;
}
Ejemplo n.º 2
0
BOOL transport_tsg_connect(rdpTransport* transport, const char* hostname, UINT16 port)
{
	rdpTsg* tsg;
	int tls_status;
	freerdp* instance;
	rdpContext* context;
	rdpSettings* settings = transport->settings;
	instance = (freerdp*) transport->settings->instance;
	context = instance->context;
	tsg = tsg_new(transport);

	if (!tsg)
		return FALSE;

	tsg->transport = transport;
	transport->tsg = tsg;
	transport->SplitInputOutput = TRUE;

	if (!transport->TlsIn)
	{
		transport->TlsIn = tls_new(settings);

		if (!transport->TlsIn)
			return FALSE;
	}

	if (!transport->TlsOut)
	{
		transport->TlsOut = tls_new(settings);

		if (!transport->TlsOut)
			return FALSE;
	}

	/* put a decent default value for gateway port */
	if (!settings->GatewayPort)
		settings->GatewayPort = 443;

	transport->TlsIn->hostname = transport->TlsOut->hostname = settings->GatewayHostname;
	transport->TlsIn->port = transport->TlsOut->port = settings->GatewayPort;
	transport->TlsIn->isGatewayTransport = TRUE;
	tls_status = tls_connect(transport->TlsIn, transport->TcpIn->bufferedBio);

	if (tls_status < 1)
	{
		if (tls_status < 0)
		{
			if (!freerdp_get_last_error(context))
				freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
		}
		else
		{
			if (!freerdp_get_last_error(context))
				freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED);
		}

		return FALSE;
	}

	transport->TlsOut->isGatewayTransport = TRUE;
	tls_status = tls_connect(transport->TlsOut, transport->TcpOut->bufferedBio);

	if (tls_status < 1)
	{
		if (tls_status < 0)
		{
			if (!freerdp_get_last_error(context))
				freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
		}
		else
		{
			if (!freerdp_get_last_error(context))
				freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED);
		}

		return FALSE;
	}

	if (!tsg_connect(tsg, hostname, port))
		return FALSE;

	transport->frontBio = BIO_new(BIO_s_tsg());
	transport->frontBio->ptr = tsg;
	return TRUE;
}
Ejemplo n.º 3
0
static int wlfreerdp_run(freerdp* instance)
{
	wlfContext* context;
	DWORD count;
	HANDLE handles[64];
	DWORD status;

	if (!instance)
		return -1;

	context = (wlfContext*)instance->context;

	if (!context)
		return -1;

	if (!freerdp_connect(instance))
	{
		printf("Failed to connect\n");
		return -1;
	}

	handle_uwac_events(instance, context->display);

	while (!freerdp_shall_disconnect(instance))
	{
		handles[0] = context->displayHandle;
		count = freerdp_get_event_handles(instance->context, &handles[1], 63);

		if (!count)
		{
			printf("Failed to get FreeRDP file descriptor\n");
			break;
		}

		status = WaitForMultipleObjects(count + 1, handles, FALSE, INFINITE);

		if (WAIT_FAILED == status)
		{
			printf("%s: WaitForMultipleObjects failed\n", __FUNCTION__);
			break;
		}

		if (!handle_uwac_events(instance, context->display))
		{
			printf("error handling UWAC events\n");
			break;
		}

		//if (WaitForMultipleObjects(count, &handles[1], FALSE, INFINITE)) {
		if (freerdp_check_event_handles(instance->context) != TRUE)
		{
			if (freerdp_get_last_error(instance->context) == FREERDP_ERROR_SUCCESS)
				printf("Failed to check FreeRDP file descriptor\n");

			break;
		}

		//}
	}

	freerdp_disconnect(instance);
	return 0;
}
Ejemplo n.º 4
0
/** Creates a new connection based on the settings found in the "instance" parameter
 *  It will use the callbacks registered on the structure to process the pre/post connect operations
 *  that the caller requires.
 *  @see struct rdp_freerdp in freerdp.h
 *
 *  @param instance - pointer to a rdp_freerdp structure that contains base information to establish the connection.
 *  				  On return, this function will be initialized with the new connection's settings.
 *
 *  @return TRUE if successful. FALSE otherwise.
 *
 */
BOOL freerdp_connect(freerdp* instance)
{
	UINT status2 = CHANNEL_RC_OK;
	rdpRdp* rdp;
	BOOL status = TRUE;
	rdpSettings* settings;
	ConnectionResultEventArgs e;

	if (!instance)
		return FALSE;

	/* We always set the return code to 0 before we start the connect sequence*/
	connectErrorCode = 0;
	instance->context->LastError = FREERDP_ERROR_SUCCESS;
	clearChannelError(instance->context);
	ResetEvent(instance->context->abortEvent);
	rdp = instance->context->rdp;
	settings = instance->settings;
	instance->context->codecs = codecs_new(instance->context);
	IFCALLRET(instance->PreConnect, status, instance);

	if (status)
		status2 = freerdp_channels_pre_connect(instance->context->channels,
		                                       instance);

	if (settings->KeyboardLayout == KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002)
	{
		settings->KeyboardType = 7;
		settings->KeyboardSubType = 2;
		settings->KeyboardFunctionKey = 12;
	}

	if (!status || (status2 != CHANNEL_RC_OK))
	{
		if (!freerdp_get_last_error(rdp->context))
			freerdp_set_last_error(instance->context, FREERDP_ERROR_PRE_CONNECT_FAILED);

		WLog_ERR(TAG, "freerdp_pre_connect failed");
		goto freerdp_connect_finally;
	}

	status = rdp_client_connect(rdp);

	/* --authonly tests the connection without a UI */
	if (instance->settings->AuthenticationOnly)
	{
		WLog_ERR(TAG, "Authentication only, exit status %"PRId32"", !status);
		goto freerdp_connect_finally;
	}

	if (!status)
		goto freerdp_connect_finally;

	if (status)
	{
		UINT status2;

		if (instance->settings->DumpRemoteFx)
		{
			instance->update->pcap_rfx = pcap_open(instance->settings->DumpRemoteFxFile,
			                                       TRUE);

			if (instance->update->pcap_rfx)
				instance->update->dump_rfx = TRUE;
		}

		IFCALLRET(instance->PostConnect, status, instance);

		if (status)
			status2 = freerdp_channels_post_connect(instance->context->channels, instance);

		if (!status || (status2 != CHANNEL_RC_OK)
		    || !update_post_connect(instance->update))
		{
			WLog_ERR(TAG, "freerdp_post_connect failed");

			if (!freerdp_get_last_error(rdp->context))
				freerdp_set_last_error(instance->context, FREERDP_ERROR_POST_CONNECT_FAILED);

			status = FALSE;
			goto freerdp_connect_finally;
		}

		if (instance->settings->PlayRemoteFx)
		{
			wStream* s;
			rdpUpdate* update;
			pcap_record record;
			update = instance->update;
			update->pcap_rfx = pcap_open(settings->PlayRemoteFxFile, FALSE);
			status = FALSE;

			if (!update->pcap_rfx)
				goto freerdp_connect_finally;
			else
				update->play_rfx = TRUE;

			status = TRUE;

			while (pcap_has_next_record(update->pcap_rfx) && status)
			{
				pcap_get_next_record_header(update->pcap_rfx, &record);

				if (!(s = StreamPool_Take(rdp->transport->ReceivePool, record.length)))
					break;

				record.data = Stream_Buffer(s);
				pcap_get_next_record_content(update->pcap_rfx, &record);
				Stream_SetLength(s, record.length);
				Stream_SetPosition(s, 0);

				if (!update->BeginPaint(update->context))
					status = FALSE;
				else if (update_recv_surfcmds(update, s) < 0)
					status = FALSE;
				else if (!update->EndPaint(update->context))
					status = FALSE;

				Stream_Release(s);
			}

			pcap_close(update->pcap_rfx);
			update->pcap_rfx = NULL;
			goto freerdp_connect_finally;
		}
	}

	if (rdp->errorInfo == ERRINFO_SERVER_INSUFFICIENT_PRIVILEGES)
		freerdp_set_last_error(instance->context,
		                       FREERDP_ERROR_INSUFFICIENT_PRIVILEGES);

	SetEvent(rdp->transport->connectedEvent);
freerdp_connect_finally:
	EventArgsInit(&e, "freerdp");
	e.result = status ? 0 : -1;
	PubSub_OnConnectionResult(instance->context->pubSub, instance->context, &e);

	if (!status)
		freerdp_disconnect(instance);

	return status;
}
Ejemplo n.º 5
0
BOOL rdp_client_connect(rdpRdp* rdp)
{
	BOOL ret;
	rdpSettings* settings = rdp->settings;

	if (rdp->settingsCopy)
	{
		freerdp_settings_free(rdp->settingsCopy);
		rdp->settingsCopy = NULL;
	}

	rdp->settingsCopy = freerdp_settings_clone(settings);

	if (!rdp->settingsCopy)
		return FALSE;

	nego_init(rdp->nego);
	nego_set_target(rdp->nego, settings->ServerHostname, settings->ServerPort);

	if (settings->GatewayEnabled)
	{
		char* user = NULL;
		char* domain = NULL;
		char* cookie = NULL;
		int user_length = 0;
		int domain_length = 0;
		int cookie_length = 0;

		if (settings->Username)
		{
			user = settings->Username;
			user_length = strlen(settings->Username);
		}

		if (settings->Domain)
			domain = settings->Domain;
		else
			domain = settings->ComputerName;

		domain_length = strlen(domain);

		cookie_length = domain_length + 1 + user_length;
		cookie = (char*) malloc(cookie_length + 1);
		if (!cookie)
			return FALSE;

		CopyMemory(cookie, domain, domain_length);
		CharUpperBuffA(cookie, domain_length);
		cookie[domain_length] = '\\';

		if (settings->Username)
			CopyMemory(&cookie[domain_length + 1], user, user_length);

		cookie[cookie_length] = '\0';

		ret = nego_set_cookie(rdp->nego, cookie);
		free(cookie);
	}
	else
	{
		ret = nego_set_cookie(rdp->nego, settings->Username);
	}

	if (!ret)
		return FALSE;

	nego_set_send_preconnection_pdu(rdp->nego, settings->SendPreconnectionPdu);
	nego_set_preconnection_id(rdp->nego, settings->PreconnectionId);
	nego_set_preconnection_blob(rdp->nego, settings->PreconnectionBlob);

	nego_set_negotiation_enabled(rdp->nego, settings->NegotiateSecurityLayer);
	nego_set_restricted_admin_mode_required(rdp->nego, settings->RestrictedAdminModeRequired);

	nego_set_gateway_enabled(rdp->nego, settings->GatewayEnabled);
	nego_set_gateway_bypass_local(rdp->nego, settings->GatewayBypassLocal);

	nego_enable_rdp(rdp->nego, settings->RdpSecurity);
	nego_enable_tls(rdp->nego, settings->TlsSecurity);
	nego_enable_nla(rdp->nego, settings->NlaSecurity);
	nego_enable_ext(rdp->nego, settings->ExtSecurity);

	if (settings->MstscCookieMode)
		settings->CookieMaxLength = MSTSC_COOKIE_MAX_LENGTH;

	nego_set_cookie_max_length(rdp->nego, settings->CookieMaxLength);

	if (settings->LoadBalanceInfo)
	{
		if (!nego_set_routing_token(rdp->nego, settings->LoadBalanceInfo, settings->LoadBalanceInfoLength))
			return FALSE;
	}

	if (!nego_connect(rdp->nego))
	{
		if (!freerdp_get_last_error(rdp->context))
		{
			freerdp_set_last_error(rdp->context, FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED);
		}

		WLog_ERR(TAG,  "Error: protocol security negotiation or connection failure");
		return FALSE;
	}

	if ((rdp->nego->selected_protocol & PROTOCOL_TLS) || (rdp->nego->selected_protocol == PROTOCOL_RDP))
	{
		if ((settings->Username != NULL) && ((settings->Password != NULL) ||
				(settings->RedirectionPassword != NULL && settings->RedirectionPasswordLength > 0)))
			settings->AutoLogonEnabled = TRUE;
	}

	rdp_set_blocking_mode(rdp, FALSE);

	rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO);
	rdp->finalize_sc_pdus = 0;

	if (!mcs_send_connect_initial(rdp->mcs))
	{
		if (!connectErrorCode)
		{
			connectErrorCode = MCSCONNECTINITIALERROR;
		}

		if (!freerdp_get_last_error(rdp->context))
		{
			freerdp_set_last_error(rdp->context, FREERDP_ERROR_MCS_CONNECT_INITIAL_ERROR);
		}

		WLog_ERR(TAG,  "Error: unable to send MCS Connect Initial");
		return FALSE;
	}

	while (rdp->state != CONNECTION_STATE_ACTIVE)
	{
		if (rdp_check_fds(rdp) < 0)
		{
			if (!freerdp_get_last_error(rdp->context))
			{
				freerdp_set_last_error(rdp->context, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
			}

			return FALSE;
		}
	}

	return TRUE;
}
Ejemplo n.º 6
0
static int rpc_channel_tls_connect(RpcChannel* channel, int timeout)
{
	int sockfd;
	rdpTls* tls;
	int tlsStatus;
	BIO* socketBio;
	BIO* bufferedBio;
	rdpRpc* rpc = channel->rpc;
	rdpContext* context = rpc->context;
	rdpSettings* settings = context->settings;
	const char* peerHostname = settings->GatewayHostname;
	UINT16 peerPort = settings->GatewayPort;
	const char *proxyUsername = settings->ProxyUsername, *proxyPassword = settings->ProxyPassword;
	BOOL isProxyConnection = proxy_prepare(settings, &peerHostname, &peerPort, &proxyUsername, &proxyPassword);
	sockfd = freerdp_tcp_connect(context, settings, peerHostname,
	                             peerPort, timeout);

	if (sockfd < 1)
		return -1;

	socketBio = BIO_new(BIO_s_simple_socket());

	if (!socketBio)
		return FALSE;

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

	if (!bufferedBio)
		return FALSE;

	bufferedBio = BIO_push(bufferedBio, socketBio);

	if (!BIO_set_nonblock(bufferedBio, TRUE))
		return -1;

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

	channel->bio = bufferedBio;
	tls = channel->tls = tls_new(settings);

	if (!tls)
		return -1;

	tls->hostname = settings->GatewayHostname;
	tls->port = settings->GatewayPort;
	tls->isGatewayTransport = TRUE;
	tlsStatus = tls_connect(tls, bufferedBio);

	if (tlsStatus < 1)
	{
		if (tlsStatus < 0)
		{
			if (!freerdp_get_last_error(context))
				freerdp_set_last_error(context, FREERDP_ERROR_TLS_CONNECT_FAILED);
		}
		else
		{
			if (!freerdp_get_last_error(context))
				freerdp_set_last_error(context, FREERDP_ERROR_CONNECT_CANCELLED);
		}

		return -1;
	}

	return 1;
}
Ejemplo n.º 7
0
BOOL rdp_client_connect(rdpRdp* rdp)
{
	BOOL status;
	rdpSettings* settings = rdp->settings;

	/* make sure SSL is initialize for earlier enough for crypto, by taking advantage of winpr SSL FIPS flag for openssl initialization */
	DWORD flags = WINPR_SSL_INIT_DEFAULT;

	if (settings->FIPSMode)
		flags |= WINPR_SSL_INIT_ENABLE_FIPS;
	winpr_InitializeSSL(flags);

	/* FIPS Mode forces the following and overrides the following(by happening later */
	/* in the command line processing): */
	/* 1. Disables NLA Security since NLA in freerdp uses NTLM(no Kerberos support yet) which uses algorithms */
	/*      not allowed in FIPS for sensitive data. So, we disallow NLA when FIPS is required. */
	/* 2. Forces the only supported RDP encryption method to be FIPS. */
	if (settings->FIPSMode || winpr_FIPSMode())
	{
		settings->NlaSecurity = FALSE;
		settings->EncryptionMethods = ENCRYPTION_METHOD_FIPS;
	}

	nego_init(rdp->nego);
	nego_set_target(rdp->nego, settings->ServerHostname, settings->ServerPort);

	if (settings->GatewayEnabled)
	{
		char* user = NULL;
		char* domain = NULL;
		char* cookie = NULL;
		int user_length = 0;
		int domain_length = 0;
		int cookie_length = 0;

		if (settings->Username)
		{
			user = settings->Username;
			user_length = strlen(settings->Username);
		}

		if (settings->Domain)
			domain = settings->Domain;
		else
			domain = settings->ComputerName;

		domain_length = strlen(domain);

		cookie_length = domain_length + 1 + user_length;
		cookie = (char*) malloc(cookie_length + 1);

		if (!cookie)
			return FALSE;

		CopyMemory(cookie, domain, domain_length);
		CharUpperBuffA(cookie, domain_length);
		cookie[domain_length] = '\\';

		if (settings->Username)
			CopyMemory(&cookie[domain_length + 1], user, user_length);

		cookie[cookie_length] = '\0';

		status = nego_set_cookie(rdp->nego, cookie);
		free(cookie);
	}
	else
	{
		status = nego_set_cookie(rdp->nego, settings->Username);
	}

	if (!status)
		return FALSE;

	nego_set_send_preconnection_pdu(rdp->nego, settings->SendPreconnectionPdu);
	nego_set_preconnection_id(rdp->nego, settings->PreconnectionId);
	nego_set_preconnection_blob(rdp->nego, settings->PreconnectionBlob);

	nego_set_negotiation_enabled(rdp->nego, settings->NegotiateSecurityLayer);
	nego_set_restricted_admin_mode_required(rdp->nego, settings->RestrictedAdminModeRequired);

	nego_set_gateway_enabled(rdp->nego, settings->GatewayEnabled);
	nego_set_gateway_bypass_local(rdp->nego, settings->GatewayBypassLocal);

	nego_enable_rdp(rdp->nego, settings->RdpSecurity);
	nego_enable_tls(rdp->nego, settings->TlsSecurity);
	nego_enable_nla(rdp->nego, settings->NlaSecurity);
	nego_enable_ext(rdp->nego, settings->ExtSecurity);

	if (settings->MstscCookieMode)
		settings->CookieMaxLength = MSTSC_COOKIE_MAX_LENGTH;

	nego_set_cookie_max_length(rdp->nego, settings->CookieMaxLength);

	if (settings->LoadBalanceInfo)
	{
		if (!nego_set_routing_token(rdp->nego, settings->LoadBalanceInfo, settings->LoadBalanceInfoLength))
			return FALSE;
	}

	rdp_client_transition_to_state(rdp, CONNECTION_STATE_NEGO);

	if (!nego_connect(rdp->nego))
	{
		if (!freerdp_get_last_error(rdp->context))
			freerdp_set_last_error(rdp->context, FREERDP_ERROR_SECURITY_NEGO_CONNECT_FAILED);

		WLog_ERR(TAG, "Error: protocol security negotiation or connection failure");
		return FALSE;
	}

	if ((rdp->nego->SelectedProtocol & PROTOCOL_TLS) || (rdp->nego->SelectedProtocol == PROTOCOL_RDP))
	{
		if ((settings->Username != NULL) && ((settings->Password != NULL) ||
				(settings->RedirectionPassword != NULL && settings->RedirectionPasswordLength > 0)))
			settings->AutoLogonEnabled = TRUE;
	}

	/* everything beyond this point is event-driven and non blocking */

	rdp->transport->ReceiveCallback = rdp_recv_callback;
	rdp->transport->ReceiveExtra = rdp;
	transport_set_blocking_mode(rdp->transport, FALSE);

	if (rdp->state != CONNECTION_STATE_NLA)
	{
		if (!mcs_client_begin(rdp->mcs))
			return FALSE;
	}

	while (rdp->state != CONNECTION_STATE_ACTIVE)
	{
		if (rdp_check_fds(rdp) < 0)
		{
			if (!freerdp_get_last_error(rdp->context))
				freerdp_set_last_error(rdp->context, FREERDP_ERROR_CONNECT_TRANSPORT_FAILED);
			return FALSE;
		}
	}

	return TRUE;
}
Ejemplo n.º 8
0
BOOL rts_connect(rdpRpc* rpc)
{
	RPC_PDU* pdu;
	rpcconn_rts_hdr_t* rts;
	HttpResponse* http_response;

	/**
	 * Connection Opening
	 *
	 * When opening a virtual connection to the server, an implementation of this protocol MUST perform
	 * the following sequence of steps:
	 *
	 * 1. Send an IN channel request as specified in section 2.1.2.1.1, containing the connection timeout,
	 *    ResourceType UUID, and Session UUID values, if any, supplied by the higher-layer protocol or application.
	 *
	 * 2. Send an OUT channel request as specified in section 2.1.2.1.2.
	 *
	 * 3. Send a CONN/A1 RTS PDU as specified in section 2.2.4.2
	 *
	 * 4. Send a CONN/B1 RTS PDU as specified in section 2.2.4.5
	 *
	 * 5. Wait for the connection establishment protocol sequence as specified in 3.2.1.5.3.1 to complete
	 *
	 * An implementation MAY execute steps 1 and 2 in parallel. An implementation SHOULD execute steps
	 * 3 and 4 in parallel. An implementation MUST execute step 3 after completion of step 1 and execute
	 * step 4 after completion of step 2.
	 *
	 */

	rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_INITIAL;
	DEBUG_RTS("VIRTUAL_CONNECTION_STATE_INITIAL");

	rpc->client->SynchronousSend = TRUE;
	rpc->client->SynchronousReceive = TRUE;

	if (!rpc_ntlm_http_out_connect(rpc))
	{
		fprintf(stderr, "rpc_out_connect_http error!\n");
		return FALSE;
	}

	if (rts_send_CONN_A1_pdu(rpc) != 0)
	{
		fprintf(stderr, "rpc_send_CONN_A1_pdu error!\n");
		return FALSE;
	}

	if (!rpc_ntlm_http_in_connect(rpc))
	{
		fprintf(stderr, "rpc_in_connect_http error!\n");
		return FALSE;
	}

	if (rts_send_CONN_B1_pdu(rpc) != 0)
	{
		fprintf(stderr, "rpc_send_CONN_B1_pdu error!\n");
		return FALSE;
	}

	rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT;
	DEBUG_RTS("VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT");

	/**
	 * Receive OUT Channel Response
	 *
	 * A client implementation MUST NOT accept the OUT channel HTTP response in any state other than
	 * Out Channel Wait. If received in any other state, this HTTP response is a protocol error. Therefore,
	 * the client MUST consider the virtual connection opening a failure and indicate this to higher layers
	 * in an implementation-specific way. The Microsoft Windows® implementation returns
	 * RPC_S_PROTOCOL_ERROR, as specified in [MS-ERREF], to higher-layer protocols.
	 *
	 * If this HTTP response is received in Out Channel Wait state, the client MUST process the fields of
	 * this response as defined in this section.
	 *
	 * First, the client MUST determine whether the response indicates a success or a failure. If the status
	 * code is set to 200, the client MUST interpret this as a success, and it MUST do the following:
	 *
	 * 1. Ignore the values of all other header fields.
	 *
	 * 2. Transition to Wait_A3W state.
	 *
	 * 3. Wait for network events.
	 *
	 * 4. Skip the rest of the processing in this section.
	 *
	 * If the status code is not set to 200, the client MUST interpret this as a failure and follow the same
	 * processing rules as specified in section 3.2.2.5.6.
	 *
	 */

	http_response = http_response_recv(rpc->TlsOut);

	if (http_response->StatusCode != HTTP_STATUS_OK)
	{
		fprintf(stderr, "rts_connect error! Status Code: %d\n", http_response->StatusCode);
		http_response_print(http_response);
		http_response_free(http_response);

		if (http_response->StatusCode == HTTP_STATUS_DENIED)
		{
			if (!connectErrorCode)
			{
				connectErrorCode = AUTHENTICATIONERROR;
			}

			if (!freerdp_get_last_error(((freerdp*)(rpc->settings->instance))->context))
			{
				freerdp_set_last_error(((freerdp*)(rpc->settings->instance))->context, FREERDP_ERROR_AUTHENTICATION_FAILED);
			}
		}

		return FALSE;
	}

	//http_response_print(http_response);
	http_response_free(http_response);

	rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_WAIT_A3W;
	DEBUG_RTS("VIRTUAL_CONNECTION_STATE_WAIT_A3W");

	/**
	 * Receive CONN_A3 RTS PDU
	 *
	 * A client implementation MUST NOT accept the CONN/A3 RTS PDU in any state other than
	 * Wait_A3W. If received in any other state, this PDU is a protocol error and the client
	 * MUST consider the virtual connection opening a failure and indicate this to higher
	 * layers in an implementation-specific way.
	 *
	 * Set the ConnectionTimeout in the Ping Originator of the Client's IN Channel to the
	 * ConnectionTimeout in the CONN/A3 PDU.
	 *
	 * If this RTS PDU is received in Wait_A3W state, the client MUST transition the state
	 * machine to Wait_C2 state and wait for network events.
	 *
	 */

	rpc_client_start(rpc);

	pdu = rpc_recv_dequeue_pdu(rpc);

	if (!pdu)
		return FALSE;

	rts = (rpcconn_rts_hdr_t*) Stream_Buffer(pdu->s);

	if (!rts_match_pdu_signature(rpc, &RTS_PDU_CONN_A3_SIGNATURE, rts))
	{
		fprintf(stderr, "Unexpected RTS PDU: Expected CONN/A3\n");
		return FALSE;
	}

	rts_recv_CONN_A3_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s));

	rpc_client_receive_pool_return(rpc, pdu);

	rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_WAIT_C2;
	DEBUG_RTS("VIRTUAL_CONNECTION_STATE_WAIT_C2");

	/**
	 * Receive CONN_C2 RTS PDU
	 *
	 * A client implementation MUST NOT accept the CONN/C2 RTS PDU in any state other than Wait_C2.
	 * If received in any other state, this PDU is a protocol error and the client MUST consider the virtual
	 * connection opening a failure and indicate this to higher layers in an implementation-specific way.
	 *
	 * If this RTS PDU is received in Wait_C2 state, the client implementation MUST do the following:
	 *
	 * 1. Transition the state machine to opened state.
	 *
	 * 2. Set the connection time-out protocol variable to the value of the ConnectionTimeout field from
	 *    the CONN/C2 RTS PDU.
	 *
	 * 3. Set the PeerReceiveWindow value in the SendingChannel of the Client IN Channel to the
	 *    ReceiveWindowSize value in the CONN/C2 PDU.
	 *
	 * 4. Indicate to higher-layer protocols that the virtual connection opening is a success.
	 *
	 */

	pdu = rpc_recv_dequeue_pdu(rpc);

	if (!pdu)
		return FALSE;

	rts = (rpcconn_rts_hdr_t*) Stream_Buffer(pdu->s);

	if (!rts_match_pdu_signature(rpc, &RTS_PDU_CONN_C2_SIGNATURE, rts))
	{
		fprintf(stderr, "Unexpected RTS PDU: Expected CONN/C2\n");
		return FALSE;
	}

	rts_recv_CONN_C2_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s));

	rpc_client_receive_pool_return(rpc, pdu);

	rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_OPENED;
	DEBUG_RTS("VIRTUAL_CONNECTION_STATE_OPENED");

	rpc->client->SynchronousSend = TRUE;
	rpc->client->SynchronousReceive = TRUE;

	return TRUE;
}
Ejemplo n.º 9
0
int freerdp_tcp_connect(rdpContext* context, rdpSettings* settings,
                        const char* hostname, int port, int timeout)
{
	int status;
	int sockfd;
	UINT32 optval;
	socklen_t optlen;
	BOOL ipcSocket = FALSE;
	BOOL useExternalDefinedSocket = FALSE;

	if (!hostname)
		return -1;

	if (hostname[0] == '/')
		ipcSocket = TRUE;

	if (hostname[0] == '|')
		useExternalDefinedSocket = TRUE;

	if (ipcSocket)
	{
		sockfd = freerdp_uds_connect(hostname);

		if (sockfd < 0)
			return -1;
	}
	else if (useExternalDefinedSocket)
		sockfd = port;
	else
	{
		sockfd = -1;

		if (!settings->GatewayEnabled)
		{
			if (!freerdp_tcp_resolve_hostname(context, hostname) || settings->RemoteAssistanceMode)
			{
				if (settings->TargetNetAddressCount > 0)
				{
					sockfd = freerdp_tcp_connect_multi(
					             context,
					             settings->TargetNetAddresses,
					             settings->TargetNetPorts,
					             settings->TargetNetAddressCount,
					             port, timeout);
				}
			}
		}

		if (sockfd <= 0)
		{
			char port_str[16];
			struct addrinfo hints;
			struct addrinfo* addr;
			struct addrinfo* result;
			ZeroMemory(&hints, sizeof(hints));
			hints.ai_family = AF_UNSPEC;
			hints.ai_socktype = SOCK_STREAM;
			sprintf_s(port_str, sizeof(port_str) - 1, "%d", port);
			status = getaddrinfo(hostname, port_str, &hints, &result);

			if (status)
			{
				if (!freerdp_get_last_error(context))
					freerdp_set_last_error(context, FREERDP_ERROR_DNS_NAME_NOT_FOUND);

				WLog_ERR(TAG, "getaddrinfo: %s", gai_strerror(status));
				return -1;
			}

			addr = result;

			if ((addr->ai_family == AF_INET6) && (addr->ai_next != 0) && !settings->PreferIPv6OverIPv4)
			{
				while ((addr = addr->ai_next))
				{
					if (addr->ai_family == AF_INET)
						break;
				}

				if (!addr)
					addr = result;
			}

			sockfd = socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);

			if (sockfd < 0)
			{
				freeaddrinfo(result);
				return -1;
			}

			if (!freerdp_tcp_connect_timeout(context, sockfd, addr->ai_addr,
			                                 addr->ai_addrlen, timeout))
			{
				freeaddrinfo(result);
				close(sockfd);
				WLog_ERR(TAG, "failed to connect to %s", hostname);
				return -1;
			}

			freeaddrinfo(result);
		}
	}

	free(settings->ClientAddress);
	settings->ClientAddress = freerdp_tcp_get_ip_address(sockfd, &settings->IPv6Enabled);

	if (!settings->ClientAddress)
	{
		if (!useExternalDefinedSocket)
			close(sockfd);

		WLog_ERR(TAG, "Couldn't get socket ip address");
		return -1;
	}

	optval = 1;
	optlen = sizeof(optval);

	if (!ipcSocket && !useExternalDefinedSocket)
	{
		if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (void*) &optval, optlen) < 0)
			WLog_ERR(TAG, "unable to set TCP_NODELAY");
	}

	/* receive buffer must be a least 32 K */
	if (getsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &optval, &optlen) == 0)
	{
		if (optval < (1024 * 32))
		{
			optval = 1024 * 32;
			optlen = sizeof(optval);

			if (setsockopt(sockfd, SOL_SOCKET, SO_RCVBUF, (void*) &optval, optlen) < 0)
			{
				close(sockfd);
				WLog_ERR(TAG, "unable to set receive buffer len");
				return -1;
			}
		}
	}

	if (!ipcSocket && !useExternalDefinedSocket)
	{
		if (!freerdp_tcp_set_keep_alive_mode(sockfd))
		{
			close(sockfd);
			WLog_ERR(TAG, "Couldn't set keep alive mode.");
			return -1;
		}
	}

	if (WaitForSingleObject(context->abortEvent, 0) == WAIT_OBJECT_0)
	{
		close(sockfd);
		return -1;
	}

	return sockfd;
}