int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length) { int CopyLength; rdpRpc* rpc; if (tsg == NULL) return -1; rpc = tsg->rpc; if (tsg->PendingPdu) { CopyLength = (length < tsg->BytesAvailable) ? length : tsg->BytesAvailable; CopyMemory(data, &tsg->pdu->s->buffer[tsg->BytesRead], CopyLength); tsg->BytesAvailable -= CopyLength; tsg->BytesRead += CopyLength; if (tsg->BytesAvailable < 1) { tsg->PendingPdu = FALSE; rpc_recv_dequeue_pdu(rpc); rpc_client_receive_pool_return(rpc, tsg->pdu); } return CopyLength; } else { tsg->pdu = rpc_recv_peek_pdu(rpc); if (!tsg->pdu) { if (tsg->rpc->client->SynchronousReceive) return tsg_read(tsg, data, length); else return 0; } tsg->PendingPdu = TRUE; tsg->BytesAvailable = Stream_Length(tsg->pdu->s); tsg->BytesRead = 0; CopyLength = (length < tsg->BytesAvailable) ? length : tsg->BytesAvailable; CopyMemory(data, &tsg->pdu->s->buffer[tsg->BytesRead], CopyLength); tsg->BytesAvailable -= CopyLength; tsg->BytesRead += CopyLength; if (tsg->BytesAvailable < 1) { tsg->PendingPdu = FALSE; rpc_recv_dequeue_pdu(rpc); rpc_client_receive_pool_return(rpc, tsg->pdu); } return CopyLength; } }
int rpc_secure_bind(rdpRpc* rpc) { int status; RPC_PDU* pdu; rpc->client->SynchronousSend = TRUE; rpc->client->SynchronousReceive = TRUE; while (rpc->State != RPC_CLIENT_STATE_CONTEXT_NEGOTIATED) { if (rpc->State == RPC_CLIENT_STATE_ESTABLISHED) { status = rpc_send_bind_pdu(rpc); if (status <= 0) { DEBUG_WARN( "rpc_secure_bind: error sending bind pdu!\n"); return -1; } rpc->State = RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK; } else if (rpc->State == RPC_CLIENT_STATE_WAIT_SECURE_BIND_ACK) { pdu = rpc_recv_dequeue_pdu(rpc); if (!pdu) { DEBUG_WARN( "rpc_secure_bind: error receiving bind ack pdu!\n"); return -1; } if (rpc_recv_bind_ack_pdu(rpc, Stream_Buffer(pdu->s), Stream_Length(pdu->s)) <= 0) { DEBUG_WARN( "rpc_secure_bind: error receiving bind ack pdu!\n"); return -1; } rpc_client_receive_pool_return(rpc, pdu); if (rpc_send_rpc_auth_3_pdu(rpc) <= 0) { DEBUG_WARN( "rpc_secure_bind: error sending rpc_auth_3 pdu!\n"); return -1; } rpc->State = RPC_CLIENT_STATE_CONTEXT_NEGOTIATED; } else { DEBUG_WARN( "rpc_secure_bind: invalid state: %d\n", rpc->State); return -1; } } rpc->client->SynchronousSend = TRUE; rpc->client->SynchronousReceive = TRUE; return 0; }
BOOL TsProxyCloseTunnelReadResponse(rdpTsg* tsg) { RPC_PDU* pdu; BYTE* buffer; UINT32 length; UINT32 offset; rdpRpc* rpc = tsg->rpc; pdu = rpc_recv_dequeue_pdu(rpc); if (!pdu) return FALSE; length = Stream_Length(pdu->s); buffer = Stream_Buffer(pdu->s); if (!(pdu->Flags & RPC_PDU_FLAG_STUB)) buffer = &buffer[24]; offset = 0; rpc_client_receive_pool_return(rpc, pdu); return TRUE; }
BOOL TsProxyCreateChannelReadResponse(rdpTsg* tsg) { RPC_PDU* pdu; BYTE* buffer; UINT32 length; UINT32 offset; rdpRpc* rpc = tsg->rpc; pdu = rpc_recv_dequeue_pdu(rpc); if (!pdu) return FALSE; length = Stream_Length(pdu->s); buffer = Stream_Buffer(pdu->s); if (!(pdu->Flags & RPC_PDU_FLAG_STUB)) buffer = &buffer[24]; offset = 0; /* ChannelContext (20 bytes) */ CopyMemory(&tsg->ChannelContext.ContextType, &buffer[offset], 4); /* ContextType (4 bytes) */ CopyMemory(tsg->ChannelContext.ContextUuid, &buffer[offset + 4], 16); /* ContextUuid (16 bytes) */ #ifdef WITH_DEBUG_TSG printf("ChannelContext:\n"); winpr_HexDump((void*) &tsg->ChannelContext, 20); printf("\n"); #endif rpc_client_receive_pool_return(rpc, pdu); 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 tsg_connect(rdpTsg* tsg, const char* hostname, UINT16 port) { RPC_PDU* pdu = NULL; RpcClientCall* call; rdpRpc* rpc = tsg->rpc; rdpSettings* settings = rpc->settings; tsg->Port = port; ConvertToUnicode(CP_UTF8, 0, hostname, -1, &tsg->Hostname, 0); ConvertToUnicode(CP_UTF8, 0, settings->ComputerName, -1, &tsg->MachineName, 0); if (!rpc_connect(rpc)) { fprintf(stderr, "rpc_connect failed!\n"); return FALSE; } DEBUG_TSG("rpc_connect success"); tsg->state = TSG_STATE_INITIAL; rpc->client->SynchronousSend = TRUE; rpc->client->SynchronousReceive = TRUE; /* * Sequential processing rules for connection process: * * 1. The RDG client MUST call TsProxyCreateTunnel to create a tunnel to the gateway. * * 2. If the call fails, the RDG client MUST end the protocol and MUST NOT perform the following steps. * * 3. The RDG client MUST initialize the following ADM elements using TsProxyCreateTunnel out parameters: * * a. The RDG client MUST initialize the ADM element Tunnel id with the tunnelId out parameter. * * b. The RDG client MUST initialize the ADM element Tunnel Context Handle with the tunnelContext * out parameter. This Tunnel Context Handle is used for subsequent tunnel-related calls. * * c. If TSGPacketResponse->packetId is TSG_PACKET_TYPE_CAPS_RESPONSE, where TSGPacketResponse is an out parameter, * * i. The RDG client MUST initialize the ADM element Nonce with TSGPacketResponse-> * TSGPacket.packetCapsResponse->pktQuarEncResponse.nonce. * * ii. The RDG client MUST initialize the ADM element Negotiated Capabilities with TSGPacketResponse-> * TSGPacket.packetCapsResponse->pktQuarEncResponse.versionCaps->TSGCaps[0].TSGPacket.TSGCapNap.capabilities. * * d. If TSGPacketResponse->packetId is TSG_PACKET_TYPE_QUARENC_RESPONSE, where TSGPacketResponse is an out parameter, * * i. The RDG client MUST initialize the ADM element Nonce with TSGPacketResponse-> * TSGPacket.packetQuarEncResponse->nonce. * * ii. The RDG client MUST initialize the ADM element Negotiated Capabilities with TSGPacketResponse-> * TSGPacket.packetQuarEncResponse->versionCaps->TSGCaps[0].TSGPacket.TSGCapNap.capabilities. * * 4. The RDG client MUST get its statement of health (SoH) by calling NAP EC API.<49> Details of the SoH format are * specified in [TNC-IF-TNCCSPBSoH]. If the SoH is received successfully, then the RDG client MUST encrypt the SoH * using the Triple Data Encryption Standard algorithm and encode it using one of PKCS #7 or X.509 encoding types, * whichever is supported by the RDG server certificate context available in the ADM element CertChainData. * * 5. The RDG client MUST copy the ADM element Nonce to TSGPacket.packetQuarRequest->data and append the encrypted SoH * message into TSGPacket.packetQuarRequest->data. The RDG client MUST set the TSGPacket.packetQuarRequest->dataLen * to the sum of the number of bytes in the encrypted SoH message and number of bytes in the ADM element Nonce, where * TSGpacket is an input parameter of TsProxyAuthorizeTunnel. The format of the packetQuarRequest field is specified * in section 2.2.9.2.1.4. */ if (!TsProxyCreateTunnel(tsg, NULL, NULL, NULL, NULL)) { tsg->state = TSG_STATE_FINAL; return FALSE; } pdu = rpc_recv_dequeue_pdu(rpc); if (!TsProxyCreateTunnelReadResponse(tsg, pdu)) { fprintf(stderr, "TsProxyCreateTunnel: error reading response\n"); return FALSE; } tsg->state = TSG_STATE_CONNECTED; /** * Sequential processing rules for connection process (continued): * * 6. The RDG client MUST call TsProxyAuthorizeTunnel to authorize the tunnel. * * 7. If the call succeeds or fails with error E_PROXY_QUARANTINE_ACCESSDENIED, follow the steps later in this section. * Else, the RDG client MUST end the protocol and MUST NOT follow the steps later in this section. * * 8. If the ADM element Negotiated Capabilities contains TSG_NAP_CAPABILITY_IDLE_TIMEOUT, then the ADM element Idle * Timeout Value SHOULD be initialized with first 4 bytes of TSGPacketResponse->TSGPacket.packetResponse->responseData * and the Statement of health response variable should be initialized with the remaining bytes of responseData, where * TSGPacketResponse is an out parameter of TsProxyAuthorizeTunnel. The format of the responseData member is specified * in section 2.2.9.2.1.5.1. * * 9. If the ADM element Negotiated Capabilities doesn't contain TSG_NAP_CAPABILITY_IDLE_TIMEOUT, then the ADM element Idle * Timeout Value SHOULD be initialized to zero and the Statement of health response variable should be initialized with all * the bytes of TSGPacketResponse->TSGPacket.packetResponse->responseData. * * 10. Verify the signature of the Statement of health response variable using SHA-1 hash and decode it using the RDG server * certificate context available in the ADM element CertChainData using one of PKCS #7 or X.509 encoding types, whichever * is supported by the RDG Server certificate. The SoHR is processed by calling the NAP EC API * INapEnforcementClientConnection::GetSoHResponse. * * 11. If the call TsProxyAuthorizeTunnel fails with error E_PROXY_QUARANTINE_ACCESSDENIED, the RDG client MUST end the protocol * and MUST NOT follow the steps later in this section. * * 12. If the ADM element Idle Timeout Value is nonzero, the RDG client SHOULD start the idle time processing as specified in * section 3.6.2.1.1 and SHOULD end the protocol when the connection has been idle for the specified Idle Timeout Value. */ if (!TsProxyAuthorizeTunnel(tsg, &tsg->TunnelContext, NULL, NULL)) { tsg->state = TSG_STATE_TUNNEL_CLOSE_PENDING; return FALSE; } pdu = rpc_recv_dequeue_pdu(rpc); if (!TsProxyAuthorizeTunnelReadResponse(tsg, pdu)) { fprintf(stderr, "TsProxyAuthorizeTunnel: error reading response\n"); return FALSE; } tsg->state = TSG_STATE_AUTHORIZED; /** * Sequential processing rules for connection process (continued): * * 13. If the ADM element Negotiated Capabilities contains TSG_MESSAGING_CAP_SERVICE_MSG, a TsProxyMakeTunnelCall call MAY be * made by the client, with TSG_TUNNEL_CALL_ASYNC_MSG_REQUEST as the parameter, to receive messages from the RDG server. * */ if (!TsProxyMakeTunnelCall(tsg, &tsg->TunnelContext, TSG_TUNNEL_CALL_ASYNC_MSG_REQUEST, NULL, NULL)) return FALSE; /** * Sequential processing rules for connection process (continued): * * 14. The RDG client MUST call TsProxyCreateChannel to create a channel to the target server name as specified by the ADM * element Target Server Name (section 3.5.1). * * 15. If the call fails, the RDG client MUST end the protocol and MUST not follow the below steps. * * 16. The RDG client MUST initialize the following ADM elements using TsProxyCreateChannel out parameters. * * a. The RDG client MUST initialize the ADM element Channel id with the channelId out parameter. * * b. The RDG client MUST initialize the ADM element Channel Context Handle with the channelContext * out parameter. This Channel Context Handle is used for subsequent channel-related calls. */ if (!TsProxyCreateChannel(tsg, &tsg->TunnelContext, NULL, NULL, NULL)) return FALSE; pdu = rpc_recv_dequeue_pdu(rpc); call = rpc_client_call_find_by_id(rpc, pdu->CallId); if (call->OpNum == TsProxyMakeTunnelCallOpnum) { if (!TsProxyMakeTunnelCallReadResponse(tsg, pdu)) { fprintf(stderr, "TsProxyMakeTunnelCall: error reading response\n"); return FALSE; } pdu = rpc_recv_dequeue_pdu(rpc); } if (!TsProxyCreateChannelReadResponse(tsg, pdu)) { fprintf(stderr, "TsProxyCreateChannel: error reading response\n"); return FALSE; } tsg->state = TSG_STATE_CHANNEL_CREATED; /** * Sequential processing rules for data transfer: * * 1. The RDG client MUST call TsProxySetupReceivePipe to receive data from the target server, via the RDG server. * * 2. The RDG client MUST call TsProxySendToServer to send data to the target server via the RDG server, and if * the Idle Timeout Timer is started, the RDG client SHOULD reset the Idle Timeout Timer. * * 3. If TsProxyMakeTunnelCall is returned, the RDG client MUST process the message and MAY call TsProxyMakeTunnelCall * again with TSG_TUNNEL_CALL_ASYNC_MSG_REQUEST as the parameter. * * 4. The RDG client MUST end the protocol after it receives the final response to TsProxySetupReceivePipe. * The final response format is specified in section 2.2.9.4.3. */ if (!TsProxySetupReceivePipe((handle_t) tsg, NULL)) return FALSE; #if 0 pdu = rpc_recv_dequeue_pdu(rpc); if (!TsProxySetupReceivePipeReadResponse(tsg, pdu)) { fprintf(stderr, "TsProxySetupReceivePipe: error reading response\n"); return FALSE; } #endif rpc->client->SynchronousSend = TRUE; rpc->client->SynchronousReceive = TRUE; fprintf(stderr, "TS Gateway Connection Success\n"); return TRUE; }
int tsg_read(rdpTsg* tsg, BYTE* data, UINT32 length) { int CopyLength; rdpRpc* rpc; if (tsg == NULL) return -1; rpc = tsg->rpc; if (rpc->transport->layer == TRANSPORT_LAYER_CLOSED) { DEBUG_WARN( "tsg_read error: connection lost\n"); return -1; } if (tsg->PendingPdu) { CopyLength = (length < tsg->BytesAvailable) ? length : tsg->BytesAvailable; CopyMemory(data, &tsg->pdu->s->buffer[tsg->BytesRead], CopyLength); tsg->BytesAvailable -= CopyLength; tsg->BytesRead += CopyLength; if (tsg->BytesAvailable < 1) { tsg->PendingPdu = FALSE; rpc_recv_dequeue_pdu(rpc); rpc_client_receive_pool_return(rpc, tsg->pdu); } return CopyLength; } tsg->pdu = rpc_recv_peek_pdu(rpc); if (!tsg->pdu) { if (!tsg->rpc->client->SynchronousReceive) return 0; // weird !!!! return tsg_read(tsg, data, length); } tsg->PendingPdu = TRUE; tsg->BytesAvailable = Stream_Length(tsg->pdu->s); tsg->BytesRead = 0; CopyLength = (length < tsg->BytesAvailable) ? length : tsg->BytesAvailable; CopyMemory(data, &tsg->pdu->s->buffer[tsg->BytesRead], CopyLength); tsg->BytesAvailable -= CopyLength; tsg->BytesRead += CopyLength; if (tsg->BytesAvailable < 1) { tsg->PendingPdu = FALSE; rpc_recv_dequeue_pdu(rpc); rpc_client_receive_pool_return(rpc, tsg->pdu); } return CopyLength; }
BOOL TsProxyAuthorizeTunnelReadResponse(rdpTsg* tsg) { RPC_PDU* pdu; BYTE* buffer; UINT32 length; UINT32 offset; UINT32 Pointer; UINT32 SizeValue; UINT32 SwitchValue; PTSG_PACKET packet; rdpRpc* rpc = tsg->rpc; PTSG_PACKET_RESPONSE packetResponse; pdu = rpc_recv_dequeue_pdu(rpc); if (!pdu) return FALSE; length = Stream_Length(pdu->s); buffer = Stream_Buffer(pdu->s); if (!(pdu->Flags & RPC_PDU_FLAG_STUB)) buffer = &buffer[24]; packet = (PTSG_PACKET) malloc(sizeof(TSG_PACKET)); ZeroMemory(packet, sizeof(TSG_PACKET)); offset = 4; packet->packetId = *((UINT32*) &buffer[offset]); /* PacketId */ SwitchValue = *((UINT32*) &buffer[offset + 4]); /* SwitchValue */ if ((packet->packetId != TSG_PACKET_TYPE_RESPONSE) || (SwitchValue != TSG_PACKET_TYPE_RESPONSE)) { printf("Unexpected PacketId: 0x%08X, Expected TSG_PACKET_TYPE_RESPONSE\n", packet->packetId); return FALSE; } packetResponse = (PTSG_PACKET_RESPONSE) malloc(sizeof(TSG_PACKET_RESPONSE)); ZeroMemory(packetResponse, sizeof(TSG_PACKET_RESPONSE)); packet->tsgPacket.packetResponse = packetResponse; Pointer = *((UINT32*) &buffer[offset + 8]); /* PacketResponsePtr */ packetResponse->flags = *((UINT32*) &buffer[offset + 12]); /* Flags */ if (packetResponse->flags != TSG_PACKET_TYPE_QUARREQUEST) { printf("Unexpected Packet Response Flags: 0x%08X, Expected TSG_PACKET_TYPE_QUARREQUEST\n", packetResponse->flags); return FALSE; } /* Reserved (4 bytes) */ Pointer = *((UINT32*) &buffer[offset + 20]); /* ResponseDataPtr */ packetResponse->responseDataLen = *((UINT32*) &buffer[offset + 24]); /* ResponseDataLength */ packetResponse->redirectionFlags.enableAllRedirections = *((UINT32*) &buffer[offset + 28]); /* EnableAllRedirections */ packetResponse->redirectionFlags.disableAllRedirections = *((UINT32*) &buffer[offset + 32]); /* DisableAllRedirections */ packetResponse->redirectionFlags.driveRedirectionDisabled = *((UINT32*) &buffer[offset + 36]); /* DriveRedirectionDisabled */ packetResponse->redirectionFlags.printerRedirectionDisabled = *((UINT32*) &buffer[offset + 40]); /* PrinterRedirectionDisabled */ packetResponse->redirectionFlags.portRedirectionDisabled = *((UINT32*) &buffer[offset + 44]); /* PortRedirectionDisabled */ packetResponse->redirectionFlags.reserved = *((UINT32*) &buffer[offset + 48]); /* Reserved */ packetResponse->redirectionFlags.clipboardRedirectionDisabled = *((UINT32*) &buffer[offset + 52]); /* ClipboardRedirectionDisabled */ packetResponse->redirectionFlags.pnpRedirectionDisabled = *((UINT32*) &buffer[offset + 56]); /* PnpRedirectionDisabled */ offset += 60; SizeValue = *((UINT32*) &buffer[offset]); offset += 4; if (SizeValue != packetResponse->responseDataLen) { printf("Unexpected size value: %d, expected: %d\n", SizeValue, packetResponse->responseDataLen); return FALSE; } offset += SizeValue; /* ResponseData */ rpc_client_receive_pool_return(rpc, pdu); free(packetResponse); free(packet); return TRUE; }
BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg) { BYTE* buffer; UINT32 count; UINT32 length; UINT32 offset; UINT32 Pointer; RPC_PDU* pdu; PTSG_PACKET packet; UINT32 SwitchValue; rdpRpc* rpc = tsg->rpc; PTSG_PACKET_CAPABILITIES tsgCaps; PTSG_PACKET_VERSIONCAPS versionCaps; PTSG_PACKET_CAPS_RESPONSE packetCapsResponse; PTSG_PACKET_QUARENC_RESPONSE packetQuarEncResponse; pdu = rpc_recv_dequeue_pdu(rpc); if (!pdu) return FALSE; length = Stream_Length(pdu->s); buffer = Stream_Buffer(pdu->s); if (!(pdu->Flags & RPC_PDU_FLAG_STUB)) buffer = &buffer[24]; packet = (PTSG_PACKET) malloc(sizeof(TSG_PACKET)); ZeroMemory(packet, sizeof(TSG_PACKET)); offset = 4; packet->packetId = *((UINT32*) &buffer[offset]); /* PacketId */ SwitchValue = *((UINT32*) &buffer[offset + 4]); /* SwitchValue */ if ((packet->packetId == TSG_PACKET_TYPE_CAPS_RESPONSE) && (SwitchValue == TSG_PACKET_TYPE_CAPS_RESPONSE)) { packetCapsResponse = (PTSG_PACKET_CAPS_RESPONSE) malloc(sizeof(TSG_PACKET_CAPS_RESPONSE)); ZeroMemory(packetCapsResponse, sizeof(TSG_PACKET_CAPS_RESPONSE)); packet->tsgPacket.packetCapsResponse = packetCapsResponse; /* PacketQuarResponsePtr (4 bytes) */ packetCapsResponse->pktQuarEncResponse.flags = *((UINT32*) &buffer[offset + 12]); /* Flags */ packetCapsResponse->pktQuarEncResponse.certChainLen = *((UINT32*) &buffer[offset + 16]); /* CertChainLength */ /* CertChainDataPtr (4 bytes) */ CopyMemory(&packetCapsResponse->pktQuarEncResponse.nonce, &buffer[offset + 24], 16); /* Nonce */ offset += 40; Pointer = *((UINT32*) &buffer[offset]); /* Ptr */ offset += 4; if ((Pointer == 0x0002000C) || (Pointer == 0x00020008)) { /* Not sure exactly what this is */ offset += 4; /* 0x00000001 (4 bytes) */ offset += 4; /* 0x00000001 (4 bytes) */ offset += 4; /* 0x00000000 (4 bytes) */ offset += 4; /* 0x00000001 (4 bytes) */ } if (packetCapsResponse->pktQuarEncResponse.certChainLen > 0) { Pointer = *((UINT32*) &buffer[offset]); /* Ptr (4 bytes): 0x00020014 */ offset += 4; offset += 4; /* MaxCount (4 bytes) */ offset += 4; /* Offset (4 bytes) */ count = *((UINT32*) &buffer[offset]); /* ActualCount (4 bytes) */ offset += 4; /* * CertChainData is a wide character string, and the count is * given in characters excluding the null terminator, therefore: * size = (count * 2) */ offset += (count * 2); /* CertChainData */ /* 4-byte alignment */ rpc_offset_align(&offset, 4); } else { Pointer = *((UINT32*) &buffer[offset]); /* Ptr (4 bytes) */ offset += 4; } versionCaps = (PTSG_PACKET_VERSIONCAPS) malloc(sizeof(TSG_PACKET_VERSIONCAPS)); ZeroMemory(versionCaps, sizeof(TSG_PACKET_VERSIONCAPS)); packetCapsResponse->pktQuarEncResponse.versionCaps = versionCaps; versionCaps->tsgHeader.ComponentId = *((UINT16*) &buffer[offset]); /* ComponentId */ versionCaps->tsgHeader.PacketId = *((UINT16*) &buffer[offset + 2]); /* PacketId */ offset += 4; if (versionCaps->tsgHeader.ComponentId != TS_GATEWAY_TRANSPORT) { printf("Unexpected ComponentId: 0x%04X, Expected TS_GATEWAY_TRANSPORT\n", versionCaps->tsgHeader.ComponentId); return FALSE; } Pointer = *((UINT32*) &buffer[offset]); /* TsgCapsPtr */ versionCaps->numCapabilities = *((UINT32*) &buffer[offset + 4]); /* NumCapabilities */ versionCaps->majorVersion = *((UINT16*) &buffer[offset + 8]); /* MajorVersion */ versionCaps->majorVersion = *((UINT16*) &buffer[offset + 10]); /* MinorVersion */ versionCaps->quarantineCapabilities = *((UINT16*) &buffer[offset + 12]); /* QuarantineCapabilities */ offset += 14; /* 4-byte alignment */ rpc_offset_align(&offset, 4); tsgCaps = (PTSG_PACKET_CAPABILITIES) malloc(sizeof(TSG_PACKET_CAPABILITIES)); ZeroMemory(tsgCaps, sizeof(TSG_PACKET_CAPABILITIES)); versionCaps->tsgCaps = tsgCaps; offset += 4; /* MaxCount (4 bytes) */ tsgCaps->capabilityType = *((UINT32*) &buffer[offset]); /* CapabilityType */ SwitchValue = *((UINT32*) &buffer[offset + 4]); /* SwitchValue */ offset += 8; if ((SwitchValue != TSG_CAPABILITY_TYPE_NAP) || (tsgCaps->capabilityType != TSG_CAPABILITY_TYPE_NAP)) { printf("Unexpected CapabilityType: 0x%08X, Expected TSG_CAPABILITY_TYPE_NAP\n", tsgCaps->capabilityType); return FALSE; } tsgCaps->tsgPacket.tsgCapNap.capabilities = *((UINT32*) &buffer[offset]); /* Capabilities */ offset += 4; /* ??? (16 bytes): all zeros */ offset += 16; /* TunnelContext (20 bytes) */ CopyMemory(&tsg->TunnelContext.ContextType, &buffer[offset], 4); /* ContextType */ CopyMemory(tsg->TunnelContext.ContextUuid, &buffer[offset + 4], 16); /* ContextUuid */ offset += 20; #ifdef WITH_DEBUG_TSG printf("TSG TunnelContext:\n"); winpr_HexDump((void*) &tsg->TunnelContext, 20); printf("\n"); #endif free(tsgCaps); free(versionCaps); free(packetCapsResponse); } else if ((packet->packetId == TSG_PACKET_TYPE_QUARENC_RESPONSE) && (SwitchValue == TSG_PACKET_TYPE_QUARENC_RESPONSE)) { packetQuarEncResponse = (PTSG_PACKET_QUARENC_RESPONSE) malloc(sizeof(TSG_PACKET_QUARENC_RESPONSE)); ZeroMemory(packetQuarEncResponse, sizeof(TSG_PACKET_QUARENC_RESPONSE)); packet->tsgPacket.packetQuarEncResponse = packetQuarEncResponse; /* PacketQuarResponsePtr (4 bytes) */ packetQuarEncResponse->flags = *((UINT32*) &buffer[offset + 12]); /* Flags */ packetQuarEncResponse->certChainLen = *((UINT32*) &buffer[offset + 16]); /* CertChainLength */ /* CertChainDataPtr (4 bytes) */ CopyMemory(&packetQuarEncResponse->nonce, &buffer[offset + 24], 16); /* Nonce */ offset += 40; if (packetQuarEncResponse->certChainLen > 0) { Pointer = *((UINT32*) &buffer[offset]); /* Ptr (4 bytes): 0x0002000C */ offset += 4; offset += 4; /* MaxCount (4 bytes) */ offset += 4; /* Offset (4 bytes) */ count = *((UINT32*) &buffer[offset]); /* ActualCount (4 bytes) */ offset += 4; /* * CertChainData is a wide character string, and the count is * given in characters excluding the null terminator, therefore: * size = (count * 2) */ offset += (count * 2); /* CertChainData */ /* 4-byte alignment */ rpc_offset_align(&offset, 4); } else { Pointer = *((UINT32*) &buffer[offset]); /* Ptr (4 bytes): 0x00020008 */ offset += 4; } versionCaps = (PTSG_PACKET_VERSIONCAPS) malloc(sizeof(TSG_PACKET_VERSIONCAPS)); ZeroMemory(versionCaps, sizeof(TSG_PACKET_VERSIONCAPS)); packetQuarEncResponse->versionCaps = versionCaps; versionCaps->tsgHeader.ComponentId = *((UINT16*) &buffer[offset]); /* ComponentId */ versionCaps->tsgHeader.PacketId = *((UINT16*) &buffer[offset + 2]); /* PacketId */ offset += 4; if (versionCaps->tsgHeader.ComponentId != TS_GATEWAY_TRANSPORT) { printf("Unexpected ComponentId: 0x%04X, Expected TS_GATEWAY_TRANSPORT\n", versionCaps->tsgHeader.ComponentId); return FALSE; } Pointer = *((UINT32*) &buffer[offset]); /* TsgCapsPtr */ versionCaps->numCapabilities = *((UINT32*) &buffer[offset + 4]); /* NumCapabilities */ versionCaps->majorVersion = *((UINT16*) &buffer[offset + 8]); /* MajorVersion */ versionCaps->majorVersion = *((UINT16*) &buffer[offset + 10]); /* MinorVersion */ versionCaps->quarantineCapabilities = *((UINT16*) &buffer[offset + 12]); /* QuarantineCapabilities */ offset += 14; /* 4-byte alignment */ rpc_offset_align(&offset, 4); /* Not sure exactly what this is */ offset += 4; /* 0x00000001 (4 bytes) */ offset += 4; /* 0x00000001 (4 bytes) */ offset += 4; /* 0x00000001 (4 bytes) */ offset += 4; /* 0x00000002 (4 bytes) */ /* TunnelContext (20 bytes) */ CopyMemory(&tsg->TunnelContext.ContextType, &buffer[offset], 4); /* ContextType */ CopyMemory(tsg->TunnelContext.ContextUuid, &buffer[offset + 4], 16); /* ContextUuid */ offset += 20; #ifdef WITH_DEBUG_TSG printf("TSG TunnelContext:\n"); winpr_HexDump((void*) &tsg->TunnelContext, 20); printf("\n"); #endif free(versionCaps); free(packetQuarEncResponse); } else { printf("Unexpected PacketId: 0x%08X, Expected TSG_PACKET_TYPE_CAPS_RESPONSE " "or TSG_PACKET_TYPE_QUARENC_RESPONSE\n", packet->packetId); return FALSE; } rpc_client_receive_pool_return(rpc, pdu); free(packet); return TRUE; }