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