BOOL rdg_in_channel_recv(rdpRdg* rdg) { BOOL status = TRUE; HttpResponse* response = NULL; switch (rdg->state) { case RDG_CLIENT_STATE_IN_CHANNEL_REQUEST: response = http_response_recv(rdg->tlsIn); if (!response) return FALSE; status = rdg_process_in_channel_response(rdg, response); http_response_free(response); break; case RDG_CLIENT_STATE_IN_CHANNEL_AUTHORIZE: response = http_response_recv(rdg->tlsIn); if (!response) return FALSE; status = rdg_process_in_channel_authorization(rdg, response); http_response_free(response); break; } return status; }
int rpc_ncacn_http_recv_in_channel_response(rdpRpc* rpc) { char* token64; int ntlm_token_length = 0; BYTE* ntlm_token_data = NULL; HttpResponse* http_response; rdpNtlm* ntlm = rpc->NtlmHttpIn->ntlm; http_response = http_response_recv(rpc->TlsIn); if (!http_response) return -1; if (ListDictionary_Contains(http_response->Authenticates, "NTLM")) { token64 = ListDictionary_GetItemValue(http_response->Authenticates, "NTLM"); if (!token64) goto out; crypto_base64_decode(token64, strlen(token64), &ntlm_token_data, &ntlm_token_length); } out: ntlm->inputBuffer[0].pvBuffer = ntlm_token_data; ntlm->inputBuffer[0].cbBuffer = ntlm_token_length; http_response_free(http_response); return 0; }
BOOL rts_connect(rdpRpc* rpc) { int status; RTS_PDU rts_pdu; HttpResponse* http_response; if (!rpc_ntlm_http_out_connect(rpc)) { printf("rpc_out_connect_http error!\n"); return FALSE; } if (!rts_send_CONN_A1_pdu(rpc)) { printf("rpc_send_CONN_A1_pdu error!\n"); return FALSE; } if (!rpc_ntlm_http_in_connect(rpc)) { printf("rpc_in_connect_http error!\n"); return FALSE; } if (!rts_send_CONN_B1_pdu(rpc)) { printf("rpc_send_CONN_B1_pdu error!\n"); return FALSE; } /* Receive OUT Channel Response */ http_response = http_response_recv(rpc->tls_out); if (http_response->StatusCode != 200) { printf("rts_connect error!\n"); http_response_print(http_response); http_response_free(http_response) ; return FALSE; } http_response_print(http_response); http_response_free(http_response); /* Receive CONN_A3 RTS PDU */ status = rts_recv_pdu(rpc, &rts_pdu); /* Receive CONN_C2 RTS PDU */ status = rts_recv_pdu(rpc, &rts_pdu); return TRUE; }
BOOL rdg_out_channel_recv(rdpRdg* rdg) { wStream* s; BOOL status = TRUE; HttpResponse* response = NULL; switch (rdg->state) { case RDG_CLIENT_STATE_OUT_CHANNEL_REQUEST: response = http_response_recv(rdg->tlsOut); if (!response) { return FALSE; } status = rdg_process_out_channel_response(rdg, response); http_response_free(response); break; case RDG_CLIENT_STATE_OUT_CHANNEL_AUTHORIZE: response = http_response_recv(rdg->tlsOut); if (!response) { return FALSE; } status = rdg_process_out_channel_authorization(rdg, response); http_response_free(response); break; default: s = rdg_receive_packet(rdg); if (s) { status = rdg_process_packet(rdg, s); Stream_Free(s, TRUE); } } return status; }
boolean rpc_ntlm_http_in_connect(rdpRpc* rpc) { STREAM* s; int ntlm_token_length; uint8* ntlm_token_data; HttpResponse* http_response; rdpNtlm* ntlm = rpc->ntlm_http_in->ntlm; ntlm_client_init(ntlm, true, rpc->settings->username, rpc->settings->domain, rpc->settings->password); ntlm_authenticate(ntlm); s = rpc_ntlm_http_request(rpc, &ntlm->outputBuffer, 0, TSG_CHANNEL_IN); /* Send IN Channel Request */ DEBUG_RPC("\n%s", s->data); tls_write_all(rpc->tls_in, s->data, s->size); stream_free(s); /* Receive IN Channel Response */ http_response = http_response_recv(rpc->tls_in); ntlm_token_data = NULL; crypto_base64_decode((uint8*) http_response->AuthParam, strlen(http_response->AuthParam), &ntlm_token_data, &ntlm_token_length); ntlm->inputBuffer.pvBuffer = ntlm_token_data; ntlm->inputBuffer.cbBuffer = ntlm_token_length; ntlm_authenticate(ntlm); http_response_free(http_response); s = rpc_ntlm_http_request(rpc, &ntlm->outputBuffer, 0x40000000, TSG_CHANNEL_IN); /* Send IN Channel Request */ DEBUG_RPC("\n%s", s->data); tls_write_all(rpc->tls_in, s->data, s->size); stream_free(s); ntlm_client_uninit(ntlm); ntlm_free(ntlm); return true; }
int rpc_ncacn_http_recv_in_channel_response(rdpRpc* rpc) { int ntlm_token_length; BYTE* ntlm_token_data; HttpResponse* http_response; rdpNtlm* ntlm = rpc->NtlmHttpIn->ntlm; http_response = http_response_recv(rpc->TlsIn); ntlm_token_data = NULL; crypto_base64_decode((BYTE*) http_response->AuthParam, strlen(http_response->AuthParam), &ntlm_token_data, &ntlm_token_length); ntlm->inputBuffer.pvBuffer = ntlm_token_data; ntlm->inputBuffer.cbBuffer = ntlm_token_length; http_response_free(http_response); return 0; }
int rpc_ncacn_http_recv_out_channel_response(rdpRpc* rpc) { int ntlm_token_length = 0; BYTE* ntlm_token_data; HttpResponse* http_response; rdpNtlm* ntlm = rpc->NtlmHttpOut->ntlm; http_response = http_response_recv(rpc->TlsOut); ntlm_token_data = NULL; if (http_response && http_response->AuthParam) { crypto_base64_decode((BYTE*) http_response->AuthParam, strlen(http_response->AuthParam), &ntlm_token_data, &ntlm_token_length); } ntlm->inputBuffer[0].pvBuffer = ntlm_token_data; ntlm->inputBuffer[0].cbBuffer = ntlm_token_length; http_response_free(http_response); return 0; }
static BOOL rdg_establish_data_connection(rdpRdg* rdg, rdpTls* tls, const char* method, const char* peerAddress, int timeout, BOOL* rpcFallback) { HttpResponse* response = NULL; int statusCode; int bodyLength; 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); if (!response) return FALSE; if (response->StatusCode == HTTP_STATUS_NOT_FOUND) { WLog_INFO(TAG, "RD Gateway does not support HTTP transport."); if (rpcFallback) *rpcFallback = TRUE; http_response_free(response); return FALSE; } 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); if (!response) return FALSE; statusCode = response->StatusCode; bodyLength = response->BodyLength; http_response_free(response); WLog_DBG(TAG, "%s authorization result: %d", method, statusCode); if (statusCode != HTTP_STATUS_OK) 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; }
BOOL rts_connect(rdpRpc* rpc) { RPC_PDU* pdu; rpcconn_rts_hdr_t* rts; HttpResponse* http_response; freerdp* instance = (freerdp*) rpc->settings->instance; rdpContext* context = instance->context; /** * 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; WLog_DBG(TAG, "VIRTUAL_CONNECTION_STATE_INITIAL"); rpc->client->SynchronousSend = TRUE; rpc->client->SynchronousReceive = TRUE; if (!rpc_ntlm_http_out_connect(rpc)) { WLog_ERR(TAG, "rpc_out_connect_http error!"); return FALSE; } if (rts_send_CONN_A1_pdu(rpc) != 0) { WLog_ERR(TAG, "rpc_send_CONN_A1_pdu error!"); return FALSE; } if (!rpc_ntlm_http_in_connect(rpc)) { WLog_ERR(TAG, "rpc_in_connect_http error!"); return FALSE; } if (rts_send_CONN_B1_pdu(rpc) < 0) { WLog_ERR(TAG, "rpc_send_CONN_B1_pdu error!"); return FALSE; } rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_OUT_CHANNEL_WAIT; WLog_DBG(TAG, "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) { WLog_ERR(TAG, "unable to retrieve OUT Channel Response!"); return FALSE; } if (http_response->StatusCode != HTTP_STATUS_OK) { WLog_ERR(TAG, "error! Status Code: %d", 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(context)) { freerdp_set_last_error(context, FREERDP_ERROR_AUTHENTICATION_FAILED); } } return FALSE; } if (http_response->bodyLen) { /* inject bytes we have read in the body as a received packet for the RPC client */ rpc->client->RecvFrag = rpc_client_fragment_pool_take(rpc); Stream_EnsureCapacity(rpc->client->RecvFrag, http_response->bodyLen); CopyMemory(rpc->client->RecvFrag, http_response->BodyContent, http_response->bodyLen); } //http_response_print(http_response); http_response_free(http_response); rpc->VirtualConnection->State = VIRTUAL_CONNECTION_STATE_WAIT_A3W; WLog_DBG(TAG, "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)) { WLog_ERR(TAG, "unexpected RTS PDU: Expected CONN/A3"); 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; WLog_DBG(TAG, "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)) { WLog_ERR(TAG, "unexpected RTS PDU: Expected CONN/C2"); 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; WLog_DBG(TAG, "VIRTUAL_CONNECTION_STATE_OPENED"); rpc->client->SynchronousSend = TRUE; rpc->client->SynchronousReceive = TRUE; return TRUE; }
BOOL rpc_ntlm_http_in_connect(rdpRpc* rpc) { STREAM* s; rdpSettings* settings; int ntlm_token_length; BYTE* ntlm_token_data; HttpResponse* http_response; rdpNtlm* ntlm = rpc->ntlm_http_in->ntlm; settings = rpc->settings; if (settings->tsg_same_credentials) { ntlm_client_init(ntlm, TRUE, settings->username, settings->domain, settings->password); ntlm_client_make_spn(ntlm, _T("HTTP"), settings->tsg_hostname); } else { ntlm_client_init(ntlm, TRUE, settings->tsg_username, settings->tsg_domain, settings->tsg_password); ntlm_client_make_spn(ntlm, _T("HTTP"), settings->tsg_hostname); } ntlm_authenticate(ntlm); s = rpc_ntlm_http_request(rpc, &ntlm->outputBuffer, 0, TSG_CHANNEL_IN); /* Send IN Channel Request */ DEBUG_RPC("\n%s", s->data); tls_write_all(rpc->tls_in, s->data, s->size); stream_free(s); /* Receive IN Channel Response */ http_response = http_response_recv(rpc->tls_in); ntlm_token_data = NULL; crypto_base64_decode((BYTE*) http_response->AuthParam, strlen(http_response->AuthParam), &ntlm_token_data, &ntlm_token_length); ntlm->inputBuffer.pvBuffer = ntlm_token_data; ntlm->inputBuffer.cbBuffer = ntlm_token_length; ntlm_authenticate(ntlm); http_response_free(http_response); s = rpc_ntlm_http_request(rpc, &ntlm->outputBuffer, 0x40000000, TSG_CHANNEL_IN); /* Send IN Channel Request */ DEBUG_RPC("\n%s", s->data); tls_write_all(rpc->tls_in, s->data, s->size); stream_free(s); ntlm_client_uninit(ntlm); ntlm_free(ntlm); return TRUE; }