コード例 #1
0
ファイル: rpc.c プロジェクト: d0rian/FreeRDP
BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* length)
{
	UINT32 alloc_hint = 0;
	rpcconn_hdr_t* header;

	*offset = RPC_COMMON_FIELDS_LENGTH;
	header = ((rpcconn_hdr_t*) buffer);

	if (header->common.ptype == PTYPE_RESPONSE)
	{
		*offset += 4;
		rpc_offset_align(offset, 8);
		alloc_hint = header->response.alloc_hint;
	}
	else if (header->common.ptype == PTYPE_REQUEST)
	{
		*offset += 4;
		rpc_offset_align(offset, 8);
		alloc_hint = header->request.alloc_hint;
	}
	else if (header->common.ptype == PTYPE_RTS)
	{
		*offset += 4;
	}
	else
	{
		return FALSE;
	}

	if (length)
	{
		if (header->common.ptype == PTYPE_REQUEST)
		{
			UINT32 sec_trailer_offset;

			/**
			 * All PDUs that carry sec_trailer information share certain common fields:
			 * frag_length and auth_length. The beginning of the sec_trailer structure
			 * for each PDU MUST be calculated to start from offset
			 * (frag_length – auth_length – 8) from the beginning of the PDU.
			 */

			sec_trailer_offset = header->common.frag_length - header->common.auth_length - 8;
			*length = sec_trailer_offset - *offset;
		}
		else
		{
			BYTE auth_pad_length;

			auth_pad_length = *(buffer + header->common.frag_length - header->common.auth_length - 6);
			*length = header->common.frag_length - (header->common.auth_length + *offset + 8 + auth_pad_length);
		}
	}

	return TRUE;
}
コード例 #2
0
ファイル: rpc_bind.c プロジェクト: JozLes77/FreeRDP
int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc)
{
	BYTE* buffer;
	UINT32 offset;
	UINT32 length;
	RpcClientCall* clientCall;
	rpcconn_rpc_auth_3_hdr_t* auth_3_pdu;

	DEBUG_RPC("Sending rpc_auth_3 PDU");

	auth_3_pdu = (rpcconn_rpc_auth_3_hdr_t*) malloc(sizeof(rpcconn_rpc_auth_3_hdr_t));
	ZeroMemory(auth_3_pdu, sizeof(rpcconn_rpc_auth_3_hdr_t));

	rpc_pdu_header_init(rpc, (rpcconn_hdr_t*) auth_3_pdu);

	auth_3_pdu->auth_length = (UINT16) rpc->ntlm->outputBuffer[0].cbBuffer;
	auth_3_pdu->auth_verifier.auth_value = rpc->ntlm->outputBuffer[0].pvBuffer;

	auth_3_pdu->ptype = PTYPE_RPC_AUTH_3;
	auth_3_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX;
	auth_3_pdu->call_id = 2;

	auth_3_pdu->max_xmit_frag = rpc->max_xmit_frag;
	auth_3_pdu->max_recv_frag = rpc->max_recv_frag;

	offset = 20;
	auth_3_pdu->auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4);

	auth_3_pdu->auth_verifier.auth_type = RPC_C_AUTHN_WINNT;
	auth_3_pdu->auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
	auth_3_pdu->auth_verifier.auth_reserved = 0x00;
	auth_3_pdu->auth_verifier.auth_context_id = 0x00000000;
	offset += (8 + auth_3_pdu->auth_length);

	auth_3_pdu->frag_length = offset;

	buffer = (BYTE*) malloc(auth_3_pdu->frag_length);

	CopyMemory(buffer, auth_3_pdu, 20);

	offset = 20;
	rpc_offset_pad(&offset, auth_3_pdu->auth_verifier.auth_pad_length);

	CopyMemory(&buffer[offset], &auth_3_pdu->auth_verifier.auth_type, 8);
	CopyMemory(&buffer[offset + 8], auth_3_pdu->auth_verifier.auth_value, auth_3_pdu->auth_length);
	offset += (8 + auth_3_pdu->auth_length);

	length = auth_3_pdu->frag_length;

	clientCall = rpc_client_call_new(auth_3_pdu->call_id, 0);
	ArrayList_Add(rpc->client->ClientCallList, clientCall);

	if (rpc_send_enqueue_pdu(rpc, buffer, length) != 0)
		length = -1;

	free(auth_3_pdu);

	return length;
}
コード例 #3
0
ファイル: rpc.c プロジェクト: 4hosi/FreeRDP
int rpc_write(rdpRpc* rpc, BYTE* data, int length, UINT16 opnum)
{
	BYTE* buffer;
	UINT32 offset;
	rdpNtlm* ntlm;
	UINT32 stub_data_pad;
	SecBuffer Buffers[2];
	SecBufferDesc Message;
	RpcClientCall* clientCall;
	SECURITY_STATUS encrypt_status;
	rpcconn_request_hdr_t* request_pdu;

	ntlm = rpc->ntlm;

	if (ntlm->table->QueryContextAttributes(&ntlm->context, SECPKG_ATTR_SIZES, &ntlm->ContextSizes) != SEC_E_OK)
	{
		printf("QueryContextAttributes SECPKG_ATTR_SIZES failure\n");
		return -1;
	}

	request_pdu = (rpcconn_request_hdr_t*) malloc(sizeof(rpcconn_request_hdr_t));
	ZeroMemory(request_pdu, sizeof(rpcconn_request_hdr_t));

	rpc_pdu_header_init(rpc, (rpcconn_hdr_t*) request_pdu);

	request_pdu->ptype = PTYPE_REQUEST;
	request_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG;
	request_pdu->auth_length = ntlm->ContextSizes.cbMaxSignature;
	request_pdu->call_id = rpc->CallId++;
	request_pdu->alloc_hint = length;
	request_pdu->p_cont_id = 0x0000;
	request_pdu->opnum = opnum;

	clientCall = rpc_client_call_new(request_pdu->call_id, request_pdu->opnum);
	ArrayList_Add(rpc->client->ClientCallList, clientCall);

	if (request_pdu->opnum == TsProxySetupReceivePipeOpnum)
		rpc->PipeCallId = request_pdu->call_id;

	request_pdu->stub_data = data;

	offset = 24;
	stub_data_pad = 0;
	stub_data_pad = rpc_offset_align(&offset, 8);

	offset += length;
	request_pdu->auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4);
	request_pdu->auth_verifier.auth_type = RPC_C_AUTHN_WINNT;
	request_pdu->auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
	request_pdu->auth_verifier.auth_reserved = 0x00;
	request_pdu->auth_verifier.auth_context_id = 0x00000000;
	offset += (8 + request_pdu->auth_length);

	request_pdu->frag_length = offset;

	buffer = (BYTE*) malloc(request_pdu->frag_length);

	CopyMemory(buffer, request_pdu, 24);

	offset = 24;
	rpc_offset_pad(&offset, stub_data_pad);
	CopyMemory(&buffer[offset], request_pdu->stub_data, length);
	offset += length;

	rpc_offset_pad(&offset, request_pdu->auth_verifier.auth_pad_length);
	CopyMemory(&buffer[offset], &request_pdu->auth_verifier.auth_type, 8);
	offset += 8;

	Buffers[0].BufferType = SECBUFFER_DATA; /* auth_data */
	Buffers[1].BufferType = SECBUFFER_TOKEN; /* signature */

	Buffers[0].pvBuffer = buffer;
	Buffers[0].cbBuffer = offset;

	Buffers[1].cbBuffer = ntlm->ContextSizes.cbMaxSignature;
	Buffers[1].pvBuffer = malloc(Buffers[1].cbBuffer);
	ZeroMemory(Buffers[1].pvBuffer, Buffers[1].cbBuffer);

	Message.cBuffers = 2;
	Message.ulVersion = SECBUFFER_VERSION;
	Message.pBuffers = (PSecBuffer) &Buffers;

	encrypt_status = ntlm->table->EncryptMessage(&ntlm->context, 0, &Message, rpc->SendSeqNum++);

	if (encrypt_status != SEC_E_OK)
	{
		printf("EncryptMessage status: 0x%08X\n", encrypt_status);
		return -1;
	}

	CopyMemory(&buffer[offset], Buffers[1].pvBuffer, Buffers[1].cbBuffer);
	offset += Buffers[1].cbBuffer;
	free(Buffers[1].pvBuffer);

	rpc_send_enqueue_pdu(rpc, buffer, request_pdu->frag_length);
	free(request_pdu);

	return length;
}
コード例 #4
0
ファイル: rpc.c プロジェクト: 4hosi/FreeRDP
BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* length)
{
	UINT32 alloc_hint = 0;
	rpcconn_hdr_t* header;

	*offset = RPC_COMMON_FIELDS_LENGTH;
	header = ((rpcconn_hdr_t*) buffer);

	if (header->common.ptype == PTYPE_RESPONSE)
	{
		*offset += 8;
		rpc_offset_align(offset, 8);
		alloc_hint = header->response.alloc_hint;
	}
	else if (header->common.ptype == PTYPE_REQUEST)
	{
		*offset += 4;
		rpc_offset_align(offset, 8);
		alloc_hint = header->request.alloc_hint;
	}
	else if (header->common.ptype == PTYPE_RTS)
	{
		*offset += 4;
	}
	else
	{
		return FALSE;
	}

	if (length)
	{
		if (header->common.ptype == PTYPE_REQUEST)
		{
			UINT32 sec_trailer_offset;

			sec_trailer_offset = header->common.frag_length - header->common.auth_length - 8;
			*length = sec_trailer_offset - *offset;
		}
		else
		{
			UINT32 frag_length;
			UINT32 auth_length;
			UINT32 auth_pad_length;
			UINT32 sec_trailer_offset;
			rpc_sec_trailer* sec_trailer;

			frag_length = header->common.frag_length;
			auth_length = header->common.auth_length;

			sec_trailer_offset = frag_length - auth_length - 8;
			sec_trailer = (rpc_sec_trailer*) &buffer[sec_trailer_offset];
			auth_pad_length = sec_trailer->auth_pad_length;

#if 0
			printf("sec_trailer: type: %d level: %d pad_length: %d reserved: %d context_id: %d\n",
					sec_trailer->auth_type,
					sec_trailer->auth_level,
					sec_trailer->auth_pad_length,
					sec_trailer->auth_reserved,
					sec_trailer->auth_context_id);
#endif

			/**
			 * According to [MS-RPCE], auth_pad_length is the number of padding
			 * octets used to 4-byte align the security trailer, but in practice
			 * we get values up to 15, which indicates 16-byte alignment.
			 */

			if ((frag_length - (sec_trailer_offset + 8)) != auth_length)
			{
				printf("invalid auth_length: actual: %d, expected: %d\n", auth_length,
						(frag_length - (sec_trailer_offset + 8)));
			}

			*length = frag_length - auth_length - 24 - 8 - auth_pad_length;
		}
	}

	return TRUE;
}
コード例 #5
0
ファイル: rpc_bind.c プロジェクト: JozLes77/FreeRDP
int rpc_send_bind_pdu(rdpRpc* rpc)
{
	BYTE* buffer;
	UINT32 offset;
	UINT32 length;
	RpcClientCall* clientCall;
	p_cont_elem_t* p_cont_elem;
	rpcconn_bind_hdr_t* bind_pdu;
	rdpSettings* settings = rpc->settings;
	BOOL promptPassword = FALSE;
	freerdp* instance = (freerdp*) settings->instance;

	DEBUG_RPC("Sending bind PDU");

	rpc->ntlm = ntlm_new();
	if (!rpc->ntlm)
		return -1;

	if ((!settings->GatewayPassword) || (!settings->GatewayUsername)
			|| (!strlen(settings->GatewayPassword)) || (!strlen(settings->GatewayUsername)))
	{
		promptPassword = TRUE;
	}

	if (promptPassword)
	{
		if (instance->GatewayAuthenticate)
		{
			BOOL proceed = instance->GatewayAuthenticate(instance,
					&settings->GatewayUsername, &settings->GatewayPassword, &settings->GatewayDomain);

			if (!proceed)
			{
				connectErrorCode = CANCELEDBYUSER;
				freerdp_set_last_error(instance->context, FREERDP_ERROR_CONNECT_CANCELLED);
				return 0;
			}

			if (settings->GatewayUseSameCredentials)
			{
				settings->Username = _strdup(settings->GatewayUsername);
				settings->Domain = _strdup(settings->GatewayDomain);
				settings->Password = _strdup(settings->GatewayPassword);

				if (!settings->Username || !settings->Domain || settings->Password)
					return -1;
			}
		}
	}

	if (!ntlm_client_init(rpc->ntlm, FALSE, settings->GatewayUsername, settings->GatewayDomain, settings->GatewayPassword, NULL) ||
		!ntlm_client_make_spn(rpc->ntlm, NULL, settings->GatewayHostname) ||
		!ntlm_authenticate(rpc->ntlm)
		)
		return -1;

	bind_pdu = (rpcconn_bind_hdr_t*) calloc(1, sizeof(rpcconn_bind_hdr_t));
	if (!bind_pdu)
		return -1;

	rpc_pdu_header_init(rpc, (rpcconn_hdr_t*) bind_pdu);

	bind_pdu->auth_length = (UINT16) rpc->ntlm->outputBuffer[0].cbBuffer;
	bind_pdu->auth_verifier.auth_value = rpc->ntlm->outputBuffer[0].pvBuffer;

	bind_pdu->ptype = PTYPE_BIND;
	bind_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_SUPPORT_HEADER_SIGN | PFC_CONC_MPX;
	bind_pdu->call_id = 2;

	bind_pdu->max_xmit_frag = rpc->max_xmit_frag;
	bind_pdu->max_recv_frag = rpc->max_recv_frag;
	bind_pdu->assoc_group_id = 0;

	bind_pdu->p_context_elem.n_context_elem = 2;
	bind_pdu->p_context_elem.reserved = 0;
	bind_pdu->p_context_elem.reserved2 = 0;

	bind_pdu->p_context_elem.p_cont_elem = malloc(sizeof(p_cont_elem_t) * bind_pdu->p_context_elem.n_context_elem);
	if (!bind_pdu->p_context_elem.p_cont_elem)
		return -1;

	p_cont_elem = &bind_pdu->p_context_elem.p_cont_elem[0];

	p_cont_elem->p_cont_id = 0;
	p_cont_elem->n_transfer_syn = 1;
	p_cont_elem->reserved = 0;
	CopyMemory(&(p_cont_elem->abstract_syntax.if_uuid), &TSGU_UUID, sizeof(p_uuid_t));
	p_cont_elem->abstract_syntax.if_version = TSGU_SYNTAX_IF_VERSION;

	p_cont_elem->transfer_syntaxes = malloc(sizeof(p_syntax_id_t));
	CopyMemory(&(p_cont_elem->transfer_syntaxes[0].if_uuid), &NDR_UUID, sizeof(p_uuid_t));
	p_cont_elem->transfer_syntaxes[0].if_version = NDR_SYNTAX_IF_VERSION;

	p_cont_elem = &bind_pdu->p_context_elem.p_cont_elem[1];

	p_cont_elem->p_cont_id = 1;
	p_cont_elem->n_transfer_syn = 1;
	p_cont_elem->reserved = 0;
	CopyMemory(&(p_cont_elem->abstract_syntax.if_uuid), &TSGU_UUID, sizeof(p_uuid_t));
	p_cont_elem->abstract_syntax.if_version = TSGU_SYNTAX_IF_VERSION;

	p_cont_elem->transfer_syntaxes = malloc(sizeof(p_syntax_id_t));
	CopyMemory(&(p_cont_elem->transfer_syntaxes[0].if_uuid), &BTFN_UUID, sizeof(p_uuid_t));
	p_cont_elem->transfer_syntaxes[0].if_version = BTFN_SYNTAX_IF_VERSION;

	offset = 116;
	bind_pdu->auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4);

	bind_pdu->auth_verifier.auth_type = RPC_C_AUTHN_WINNT;
	bind_pdu->auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
	bind_pdu->auth_verifier.auth_reserved = 0x00;
	bind_pdu->auth_verifier.auth_context_id = 0x00000000;
	offset += (8 + bind_pdu->auth_length);

	bind_pdu->frag_length = offset;

	buffer = (BYTE*) malloc(bind_pdu->frag_length);
	if (!buffer)
		return -1;

	CopyMemory(buffer, bind_pdu, 24);
	CopyMemory(&buffer[24], &bind_pdu->p_context_elem, 4);
	CopyMemory(&buffer[28], &bind_pdu->p_context_elem.p_cont_elem[0], 24);
	CopyMemory(&buffer[52], bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes, 20);
	CopyMemory(&buffer[72], &bind_pdu->p_context_elem.p_cont_elem[1], 24);
	CopyMemory(&buffer[96], bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes, 20);

	offset = 116;
	rpc_offset_pad(&offset, bind_pdu->auth_verifier.auth_pad_length);

	CopyMemory(&buffer[offset], &bind_pdu->auth_verifier.auth_type, 8);
	CopyMemory(&buffer[offset + 8], bind_pdu->auth_verifier.auth_value, bind_pdu->auth_length);
	offset += (8 + bind_pdu->auth_length);

	length = bind_pdu->frag_length;

	clientCall = rpc_client_call_new(bind_pdu->call_id, 0);
	if (!clientCall)
		return -1;
	if (ArrayList_Add(rpc->client->ClientCallList, clientCall) < 0)
		return -1;

	if (rpc_send_enqueue_pdu(rpc, buffer, length) != 0)
		length = -1;

	free(bind_pdu->p_context_elem.p_cont_elem[0].transfer_syntaxes);
	free(bind_pdu->p_context_elem.p_cont_elem[1].transfer_syntaxes);
	free(bind_pdu->p_context_elem.p_cont_elem);
	free(bind_pdu);

	return length;
}
コード例 #6
0
ファイル: rpc_bind.c プロジェクト: 99455125/FreeRDP
int rpc_send_rpc_auth_3_pdu(rdpRpc* rpc)
{
	int status = -1;
	BYTE* buffer;
	UINT32 offset;
	UINT32 length;
	RpcClientCall* clientCall;
	rpcconn_rpc_auth_3_hdr_t* auth_3_pdu;
	RpcVirtualConnection* connection = rpc->VirtualConnection;
	RpcInChannel* inChannel = connection->DefaultInChannel;

	WLog_DBG(TAG, "Sending RpcAuth3 PDU");

	auth_3_pdu = (rpcconn_rpc_auth_3_hdr_t*) calloc(1, sizeof(rpcconn_rpc_auth_3_hdr_t));

	if (!auth_3_pdu)
		return -1;

	rpc_pdu_header_init(rpc, (rpcconn_hdr_t*) auth_3_pdu);

	auth_3_pdu->auth_length = (UINT16) rpc->ntlm->outputBuffer[0].cbBuffer;
	auth_3_pdu->auth_verifier.auth_value = rpc->ntlm->outputBuffer[0].pvBuffer;

	auth_3_pdu->ptype = PTYPE_RPC_AUTH_3;
	auth_3_pdu->pfc_flags = PFC_FIRST_FRAG | PFC_LAST_FRAG | PFC_CONC_MPX;
	auth_3_pdu->call_id = 2;

	auth_3_pdu->max_xmit_frag = rpc->max_xmit_frag;
	auth_3_pdu->max_recv_frag = rpc->max_recv_frag;

	offset = 20;
	auth_3_pdu->auth_verifier.auth_pad_length = rpc_offset_align(&offset, 4);

	auth_3_pdu->auth_verifier.auth_type = RPC_C_AUTHN_WINNT;
	auth_3_pdu->auth_verifier.auth_level = RPC_C_AUTHN_LEVEL_PKT_INTEGRITY;
	auth_3_pdu->auth_verifier.auth_reserved = 0x00;
	auth_3_pdu->auth_verifier.auth_context_id = 0x00000000;
	offset += (8 + auth_3_pdu->auth_length);

	auth_3_pdu->frag_length = offset;

	buffer = (BYTE*) malloc(auth_3_pdu->frag_length);

	if (!buffer)
		return -1;

	CopyMemory(buffer, auth_3_pdu, 20);

	offset = 20;
	rpc_offset_pad(&offset, auth_3_pdu->auth_verifier.auth_pad_length);

	CopyMemory(&buffer[offset], &auth_3_pdu->auth_verifier.auth_type, 8);
	CopyMemory(&buffer[offset + 8], auth_3_pdu->auth_verifier.auth_value, auth_3_pdu->auth_length);
	offset += (8 + auth_3_pdu->auth_length);

	length = auth_3_pdu->frag_length;

	clientCall = rpc_client_call_new(auth_3_pdu->call_id, 0);
	if (ArrayList_Add(rpc->client->ClientCallList, clientCall) >= 0)
	{
		status = rpc_in_channel_send_pdu(inChannel, buffer, length);
	}

	free(auth_3_pdu);
	free(buffer);

	return (status > 0) ? 1 : -1;
}
コード例 #7
0
ファイル: tsg.c プロジェクト: AlessioLeo/FreeRDP
BOOL TsProxyAuthorizeTunnelWriteRequest(rdpTsg* tsg, PTUNNEL_CONTEXT_HANDLE_NOSERIALIZE tunnelContext)
{
	UINT32 pad;
	int status;
	BYTE* buffer;
	UINT32 count;
	UINT32 length;
	UINT32 offset;
	CONTEXT_HANDLE* handle;
	rdpRpc* rpc = tsg->rpc;

	count = _wcslen(tsg->MachineName) + 1;

	offset = 64 + (count * 2);
	rpc_offset_align(&offset, 4);
	offset += 4;

	length = offset;
	buffer = (BYTE*) malloc(length);

	/* TunnelContext */
	handle = (CONTEXT_HANDLE*) tunnelContext;
	CopyMemory(&buffer[0], &handle->ContextType, 4); /* ContextType */
	CopyMemory(&buffer[4], handle->ContextUuid, 16); /* ContextUuid */

	/* 4-byte alignment */

	*((UINT32*) &buffer[20]) = TSG_PACKET_TYPE_QUARREQUEST; /* PacketId */
	*((UINT32*) &buffer[24]) = TSG_PACKET_TYPE_QUARREQUEST; /* SwitchValue */

	*((UINT32*) &buffer[28]) = 0x00020000; /* PacketQuarRequestPtr */

	*((UINT32*) &buffer[32]) = 0x00000000; /* Flags */

	*((UINT32*) &buffer[36]) = 0x00020004; /* MachineNamePtr */

	*((UINT32*) &buffer[40]) = count; /* NameLength */

	*((UINT32*) &buffer[44]) = 0x00020008; /* DataPtr */
	*((UINT32*) &buffer[48]) = 0; /* DataLength */

	/* MachineName */
	*((UINT32*) &buffer[52]) = count; /* MaxCount */
	*((UINT32*) &buffer[56]) = 0; /* Offset */
	*((UINT32*) &buffer[60]) = count; /* ActualCount */
	CopyMemory(&buffer[64], tsg->MachineName, count * 2); /* Array */
	offset = 64 + (count * 2);

	/* 4-byte alignment */
	pad = rpc_offset_align(&offset, 4);
	ZeroMemory(&buffer[offset - pad], pad);

	*((UINT32*) &buffer[offset]) = 0x00000000; /* MaxCount */
	offset += 4;

	status = rpc_write(rpc, buffer, length, TsProxyAuthorizeTunnelOpnum);

	if (status <= 0)
		return FALSE;

	free(buffer);

	return TRUE;
}
コード例 #8
0
ファイル: tsg.c プロジェクト: AlessioLeo/FreeRDP
BOOL TsProxyCreateTunnelReadResponse(rdpTsg* tsg, RPC_PDU* pdu)
{
	BYTE* buffer;
	UINT32 count;
	UINT32 length;
	UINT32 offset;
	UINT32 Pointer;
	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;

	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)
		{
			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->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))
		{
			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;

		/* ??? (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
		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;
}
コード例 #9
0
ファイル: rpc.c プロジェクト: Matrix42AG/FreeRDP
BOOL rpc_get_stub_data_info(rdpRpc* rpc, BYTE* buffer, UINT32* offset, UINT32* length)
{
	UINT32 alloc_hint = 0;
	rpcconn_hdr_t* header;
	UINT32 frag_length;
	UINT32 auth_length;
	UINT32 auth_pad_length;
	UINT32 sec_trailer_offset;
	rpc_sec_trailer* sec_trailer;
	*offset = RPC_COMMON_FIELDS_LENGTH;
	header = ((rpcconn_hdr_t*) buffer);

	switch (header->common.ptype)
	{
		case PTYPE_RESPONSE:
			*offset += 8;
			rpc_offset_align(offset, 8);
			alloc_hint = header->response.alloc_hint;
			break;

		case PTYPE_REQUEST:
			*offset += 4;
			rpc_offset_align(offset, 8);
			alloc_hint = header->request.alloc_hint;
			break;

		case PTYPE_RTS:
			*offset += 4;
			break;

		default:
			WLog_ERR(TAG, "Unknown PTYPE: 0x%02"PRIX8"", header->common.ptype);
			return FALSE;
	}

	if (!length)
		return TRUE;

	if (header->common.ptype == PTYPE_REQUEST)
	{
		UINT32 sec_trailer_offset;
		sec_trailer_offset = header->common.frag_length - header->common.auth_length - 8;
		*length = sec_trailer_offset - *offset;
		return TRUE;
	}

	frag_length = header->common.frag_length;
	auth_length = header->common.auth_length;
	sec_trailer_offset = frag_length - auth_length - 8;
	sec_trailer = (rpc_sec_trailer*) &buffer[sec_trailer_offset];
	auth_pad_length = sec_trailer->auth_pad_length;
#if 0
	WLog_DBG(TAG,
	         "sec_trailer: type: %"PRIu8" level: %"PRIu8" pad_length: %"PRIu8" reserved: %"PRIu8" context_id: %"PRIu32"",
	         sec_trailer->auth_type, sec_trailer->auth_level,
	         sec_trailer->auth_pad_length, sec_trailer->auth_reserved,
	         sec_trailer->auth_context_id);
#endif

	/**
	 * According to [MS-RPCE], auth_pad_length is the number of padding
	 * octets used to 4-byte align the security trailer, but in practice
	 * we get values up to 15, which indicates 16-byte alignment.
	 */

	if ((frag_length - (sec_trailer_offset + 8)) != auth_length)
	{
		WLog_ERR(TAG, "invalid auth_length: actual: %"PRIu32", expected: %"PRIu32"", auth_length,
		         (frag_length - (sec_trailer_offset + 8)));
	}

	*length = frag_length - auth_length - 24 - 8 - auth_pad_length;
	return TRUE;
}
コード例 #10
0
ファイル: tsg.c プロジェクト: C-o-r-E/FreeRDP
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;
}