HRESULT TsProxyCloseTunnel(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_SERIALIZE* context) { RPC_PDU* pdu = NULL; /** * HRESULT TsProxyCloseTunnel( * [in, out] PTUNNEL_CONTEXT_HANDLE_SERIALIZE* context * ); */ DEBUG_TSG("TsProxyCloseTunnel"); if (!TsProxyCloseTunnelWriteRequest(tsg, context)) { fprintf(stderr, "TsProxyCloseTunnel: error writing request\n"); return FALSE; } if (!TsProxyCloseTunnelReadResponse(tsg, pdu)) { fprintf(stderr, "TsProxyCloseTunnel: error reading response\n"); return FALSE; } return TRUE; }
BOOL TsProxyCreateChannel(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext, PTSENDPOINTINFO tsEndPointInfo, PCHANNEL_CONTEXT_HANDLE_SERIALIZE* channelContext, UINT32* channelId) { /** * OpNum = 4 * * HRESULT TsProxyCreateChannel( * [in] PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext, * [in, ref] PTSENDPOINTINFO tsEndPointInfo, * [out] PCHANNEL_CONTEXT_HANDLE_SERIALIZE* channelContext, * [out] unsigned long* channelId * ); */ DEBUG_TSG("TsProxyCreateChannel"); if (!TsProxyCreateChannelWriteRequest(tsg, tunnelContext)) { printf("TsProxyCreateChannel: error writing request\n"); return FALSE; } if (!TsProxyCreateChannelReadResponse(tsg)) { printf("TsProxyCreateChannel: error reading response\n"); return FALSE; } return TRUE; }
BOOL TsProxyMakeTunnelCall(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext, UINT32 procId, PTSG_PACKET tsgPacket, PTSG_PACKET* tsgPacketResponse) { /** * OpNum = 3 * * HRESULT TsProxyMakeTunnelCall( * [in] PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext, * [in] unsigned long procId, * [in, ref] PTSG_PACKET tsgPacket, * [out, ref] PTSG_PACKET* tsgPacketResponse * ); */ DEBUG_TSG("TsProxyMakeTunnelCall"); if (!TsProxyMakeTunnelCallWriteRequest(tsg, tunnelContext, procId)) { printf("TsProxyMakeTunnelCall: error writing request\n"); return FALSE; } if (!TsProxyMakeTunnelCallReadResponse(tsg)) { printf("TsProxyMakeTunnelCall: error reading response\n"); return FALSE; } return TRUE; }
BOOL TsProxyAuthorizeTunnel(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext, PTSG_PACKET tsgPacket, PTSG_PACKET* tsgPacketResponse) { /** * OpNum = 2 * * HRESULT TsProxyAuthorizeTunnel( * [in] PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext, * [in, ref] PTSG_PACKET tsgPacket, * [out, ref] PTSG_PACKET* tsgPacketResponse * ); * */ DEBUG_TSG("TsProxyAuthorizeTunnel"); if (!TsProxyAuthorizeTunnelWriteRequest(tsg, tunnelContext)) { printf("TsProxyAuthorizeTunnel: error writing request\n"); return FALSE; } if (!TsProxyAuthorizeTunnelReadResponse(tsg)) { printf("TsProxyAuthorizeTunnel: error reading response\n"); return FALSE; } return TRUE; }
BOOL TsProxyCreateTunnel(rdpTsg* tsg, PTSG_PACKET tsgPacket, PTSG_PACKET* tsgPacketResponse, PTUNNEL_CONTEXT_HANDLE_SERIALIZE* tunnelContext, UINT32* tunnelId) { /** * OpNum = 1 * * HRESULT TsProxyCreateTunnel( * [in, ref] PTSG_PACKET tsgPacket, * [out, ref] PTSG_PACKET* tsgPacketResponse, * [out] PTUNNEL_CONTEXT_HANDLE_SERIALIZE* tunnelContext, * [out] unsigned long* tunnelId * ); */ DEBUG_TSG("TsProxyCreateTunnel"); if (!TsProxyCreateTunnelWriteRequest(tsg)) { printf("TsProxyCreateTunnel: error writing request\n"); return FALSE; } if (!TsProxyCreateTunnelReadResponse(tsg)) { printf("TsProxyCreateTunnel: error reading response\n"); return FALSE; } return TRUE; }
BOOL TsProxySetupReceivePipe(handle_t IDL_handle, BYTE* pRpcMessage) { rdpTsg* tsg; /** * OpNum = 8 * * DWORD TsProxySetupReceivePipe( * [in, max_is(32767)] byte pRpcMessage[] * ); */ tsg = (rdpTsg*) IDL_handle; DEBUG_TSG("TsProxySetupReceivePipe"); if (!TsProxySetupReceivePipeWriteRequest(tsg)) { printf("TsProxySetupReceivePipe: error writing request\n"); return FALSE; } if (!TsProxySetupReceivePipeReadResponse(tsg)) { printf("TsProxySetupReceivePipe: error reading response\n"); return FALSE; } return TRUE; }
HRESULT TsProxyCloseChannel(rdpTsg* tsg, PCHANNEL_CONTEXT_HANDLE_NOSERIALIZE* context) { /** * HRESULT TsProxyCloseChannel( * [in, out] PCHANNEL_CONTEXT_HANDLE_NOSERIALIZE* context * ); */ DEBUG_TSG("TsProxyCloseChannel"); if (!TsProxyCloseChannelWriteRequest(tsg, context)) { printf("TsProxyCloseChannel: error writing request\n"); return FALSE; } if (!TsProxyCloseChannelReadResponse(tsg)) { printf("TsProxyCloseChannel: error reading response\n"); return FALSE; } 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; }
BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu) { BYTE* buffer; UINT32 count; UINT32 length; UINT32 offset; UINT32 Pointer; PTSG_PACKET packet; UINT32 SwitchValue; UINT32 MessageSwitchValue; UINT32 IsMessagePresent; UINT32 MsgBytes; rdpRpc* rpc = tsg->rpc; PTSG_PACKET_CAPABILITIES tsgCaps; PTSG_PACKET_VERSIONCAPS versionCaps; PTSG_PACKET_CAPS_RESPONSE packetCapsResponse; PTSG_PACKET_QUARENC_RESPONSE packetQuarEncResponse; 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; // Skip Packet Pointer 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]); /* VersionCapsPtr */ offset += 4; if ((Pointer == 0x0002000C) || (Pointer == 0x00020008)) { offset += 4; /* MsgID */ offset += 4; /* MsgType */ IsMessagePresent = *((UINT32*) &buffer[offset]); offset += 4; MessageSwitchValue = *((UINT32*) &buffer[offset]); DEBUG_TSG("IsMessagePresent %d MessageSwitchValue %d", IsMessagePresent, MessageSwitchValue); offset += 4; } if (packetCapsResponse->pktQuarEncResponse.certChainLen > 0) { Pointer = *((UINT32*) &buffer[offset]); /* MsgPtr (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) { fprintf(stderr, "Unexpected ComponentId: 0x%04X, Expected TS_GATEWAY_TRANSPORT\n", versionCaps->tsgHeader.ComponentId); free(packetCapsResponse); free(versionCaps); free(packet); return FALSE; } Pointer = *((UINT32*) &buffer[offset]); /* TsgCapsPtr */ versionCaps->numCapabilities = *((UINT32*) &buffer[offset + 4]); /* NumCapabilities */ versionCaps->majorVersion = *((UINT16*) &buffer[offset + 8]); /* MajorVersion */ versionCaps->minorVersion = *((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)) { fprintf(stderr, "Unexpected CapabilityType: 0x%08X, Expected TSG_CAPABILITY_TYPE_NAP\n", tsgCaps->capabilityType); free(tsgCaps); free(versionCaps); free(packetCapsResponse); free(packet); return FALSE; } tsgCaps->tsgPacket.tsgCapNap.capabilities = *((UINT32*) &buffer[offset]); /* Capabilities */ offset += 4; switch(MessageSwitchValue) { case TSG_ASYNC_MESSAGE_CONSENT_MESSAGE: case TSG_ASYNC_MESSAGE_SERVICE_MESSAGE: offset += 4; // IsDisplayMandatory offset += 4; // IsConsent Mandatory MsgBytes = *((UINT32*) &buffer[offset]); offset += 4; Pointer = *((UINT32*) &buffer[offset]); offset += 4; if(Pointer) { offset += 4; // MaxCount offset += 8; // UnicodeString Offset, Length } if(MsgBytes > TSG_MESSAGING_MAX_MESSAGE_LENGTH) { fprintf(stderr, "Out of Spec Message Length %d"); return FALSE; } offset += MsgBytes; break; case TSG_ASYNC_MESSAGE_REAUTH: rpc_offset_align(&offset, 8); offset += 8; // UINT64 TunnelContext, not to be confused with // the ContextHandle TunnelContext below. break; default: fprintf(stderr, "Unexpected Message Type: 0x%X\n", MessageSwitchValue); return FALSE; } rpc_offset_align(&offset, 4); /* TunnelContext (20 bytes) */ CopyMemory(&tsg->TunnelContext.ContextType, &buffer[offset], 4); /* ContextType */ CopyMemory(tsg->TunnelContext.ContextUuid, &buffer[offset + 4], 16); /* ContextUuid */ offset += 20; // UINT32 TunnelId // HRESULT ReturnValue #ifdef WITH_DEBUG_TSG fprintf(stderr, "TSG TunnelContext:\n"); winpr_HexDump((void*) &tsg->TunnelContext, 20); fprintf(stderr, "\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) { fprintf(stderr, "Unexpected ComponentId: 0x%04X, Expected TS_GATEWAY_TRANSPORT\n", versionCaps->tsgHeader.ComponentId); free(versionCaps); free(packetQuarEncResponse); free(packet); 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 fprintf(stderr, "TSG TunnelContext:\n"); winpr_HexDump((void*) &tsg->TunnelContext, 20); fprintf(stderr, "\n"); #endif free(versionCaps); free(packetQuarEncResponse); } else { fprintf(stderr, "Unexpected PacketId: 0x%08X, Expected TSG_PACKET_TYPE_CAPS_RESPONSE " "or TSG_PACKET_TYPE_QUARENC_RESPONSE\n", packet->packetId); free(packet); return FALSE; } rpc_client_receive_pool_return(rpc, pdu); free(packet); return TRUE; }