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; }
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; }
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; }
/** 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; }
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; }
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; }
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; }
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; }
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; }