int rpc_recv_pdu_header(rdpRpc* rpc, BYTE* header) { int status; int bytesRead; UINT32 offset; /* Read common header fields */ bytesRead = 0; while (bytesRead < RPC_COMMON_FIELDS_LENGTH) { status = rpc_out_read(rpc, &header[bytesRead], RPC_COMMON_FIELDS_LENGTH - bytesRead); if (status < 0) { printf("rpc_recv_pdu_header: error reading header\n"); return status; } bytesRead += status; } rpc_get_stub_data_info(rpc, header, &offset, NULL); while (bytesRead < offset) { status = rpc_out_read(rpc, &header[bytesRead], offset - bytesRead); if (status < 0) return status; bytesRead += status; } return bytesRead; }
int rpc_recv_bind_ack_pdu(rdpRpc* rpc) { BYTE* p; STREAM* s; int status; BYTE* pdu; BYTE* auth_data; RPC_PDU_HEADER header; int pdu_length = 0x8FFF; pdu = malloc(pdu_length); if (pdu == NULL) return -1; status = rpc_out_read(rpc, pdu, pdu_length); if (status > 0) { s = stream_new(0); stream_attach(s, pdu, pdu_length); rpc_pdu_header_read(s, &header); stream_detach(s); stream_free(s); auth_data = malloc(header.auth_length); if (auth_data == NULL) { free(pdu); return -1; } p = (pdu + (header.frag_length - header.auth_length)); memcpy(auth_data, p, header.auth_length); rpc->ntlm->inputBuffer.pvBuffer = auth_data; rpc->ntlm->inputBuffer.cbBuffer = header.auth_length; ntlm_authenticate(rpc->ntlm); } free(pdu); return status; }
int rpc_client_on_read_event(rdpRpc* rpc) { int position; int status = -1; rpcconn_common_hdr_t* header; if (!rpc->client->RecvFrag) rpc->client->RecvFrag = rpc_client_fragment_pool_take(rpc); position = Stream_GetPosition(rpc->client->RecvFrag); if (Stream_GetPosition(rpc->client->RecvFrag) < RPC_COMMON_FIELDS_LENGTH) { status = rpc_out_read(rpc, Stream_Pointer(rpc->client->RecvFrag), RPC_COMMON_FIELDS_LENGTH - Stream_GetPosition(rpc->client->RecvFrag)); if (status < 0) { fprintf(stderr, "rpc_client_frag_read: error reading header\n"); return -1; } Stream_Seek(rpc->client->RecvFrag, status); } if (Stream_GetPosition(rpc->client->RecvFrag) >= RPC_COMMON_FIELDS_LENGTH) { header = (rpcconn_common_hdr_t*) Stream_Buffer(rpc->client->RecvFrag); if (header->frag_length > rpc->max_recv_frag) { fprintf(stderr, "rpc_client_frag_read: invalid fragment size: %d (max: %d)\n", header->frag_length, rpc->max_recv_frag); winpr_HexDump(Stream_Buffer(rpc->client->RecvFrag), Stream_GetPosition(rpc->client->RecvFrag)); return -1; } if (Stream_GetPosition(rpc->client->RecvFrag) < header->frag_length) { status = rpc_out_read(rpc, Stream_Pointer(rpc->client->RecvFrag), header->frag_length - Stream_GetPosition(rpc->client->RecvFrag)); if (status < 0) { fprintf(stderr, "rpc_client_frag_read: error reading fragment body\n"); return -1; } Stream_Seek(rpc->client->RecvFrag, status); } } else { return status; } if (status < 0) return -1; status = Stream_GetPosition(rpc->client->RecvFrag) - position; if (Stream_GetPosition(rpc->client->RecvFrag) >= header->frag_length) { /* complete fragment received */ Stream_Length(rpc->client->RecvFrag) = Stream_GetPosition(rpc->client->RecvFrag); Stream_SetPosition(rpc->client->RecvFrag, 0); Queue_Enqueue(rpc->client->FragmentQueue, rpc->client->RecvFrag); rpc->client->RecvFrag = NULL; rpc_client_on_fragment_received_event(rpc); } return status; }
int rpc_read(rdpRpc* rpc, uint8* data, int length) { int status; int read = 0; int data_length; uint16 frag_length; uint16 auth_length; uint8 auth_pad_length; uint32 call_id = -1; int rpc_length = length + 0xFF; uint8* rpc_data = xmalloc(rpc_length); if (rpc_data == NULL) { printf("rpc_read error: memory allocation failed\n") ; return -1 ; } if (rpc->read_buffer_len > 0) { if (rpc->read_buffer_len > (uint32) length) { printf("rpc_read error: receiving buffer is not large enough\n"); xfree(rpc_data) ; return -1; } memcpy(data, rpc->read_buffer, rpc->read_buffer_len); read += rpc->read_buffer_len; xfree(rpc->read_buffer); rpc->read_buffer_len = 0; } while (true) { status = rpc_out_read(rpc, rpc_data, rpc_length); if (status == 0) { xfree(rpc_data); return read; } else if (status < 0) { printf("Error! rpc_out_read() returned negative value. BytesSent: %d, BytesReceived: %d\n", rpc->VirtualConnection->DefaultInChannel->BytesSent, rpc->VirtualConnection->DefaultOutChannel->BytesReceived); xfree(rpc_data); return status; } frag_length = *(uint16*)(rpc_data + 8); auth_length = *(uint16*)(rpc_data + 10); call_id = *(uint32*)(rpc_data + 12); status = *(uint32*)(rpc_data + 16); /* alloc_hint */ auth_pad_length = *(rpc_data + frag_length - auth_length - 6); /* -6 = -8 + 2 (sec_trailer + 2) */ /* data_length must be calculated because alloc_hint carries size of more than one pdu */ data_length = frag_length - auth_length - 24 - 8 - auth_pad_length; /* 24 is header; 8 is sec_trailer */ if (status == 4) continue; if (read + data_length > length) /* if read data is greater then given buffer */ { rpc->read_buffer_len = read + data_length - length; rpc->read_buffer = xmalloc(rpc->read_buffer_len); data_length -= rpc->read_buffer_len; memcpy(rpc->read_buffer, rpc_data + 24 + data_length, rpc->read_buffer_len); } memcpy(data + read, rpc_data + 24, data_length); read += data_length; if (status > data_length && read < length) continue; break; } xfree(rpc_data); return read; }
int rpc_recv_pdu_fragment(rdpRpc* rpc) { int status; int headerLength; int bytesRead = 0; rpcconn_hdr_t* header; WaitForSingleObject(rpc->VirtualConnection->DefaultInChannel->Mutex, INFINITE); status = rpc_recv_pdu_header(rpc, rpc->FragBuffer); if (status < 1) { printf("rpc_recv_pdu_header: error reading header\n"); return status; } headerLength = status; header = (rpcconn_hdr_t*) rpc->FragBuffer; bytesRead += status; if (header->common.frag_length > rpc->FragBufferSize) { rpc->FragBufferSize = header->common.frag_length; rpc->FragBuffer = (BYTE*) realloc(rpc->FragBuffer, rpc->FragBufferSize); header = (rpcconn_hdr_t*) rpc->FragBuffer; } while (bytesRead < header->common.frag_length) { status = rpc_out_read(rpc, &rpc->FragBuffer[bytesRead], header->common.frag_length - bytesRead); if (status < 0) { printf("rpc_recv_pdu: error reading fragment\n"); return status; } bytesRead += status; } ReleaseMutex(rpc->VirtualConnection->DefaultInChannel->Mutex); if (header->common.ptype == PTYPE_RTS) /* RTS PDU */ { if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED) return header->common.frag_length; printf("Receiving Out-of-Sequence RTS PDU\n"); rts_recv_out_of_sequence_pdu(rpc, rpc->FragBuffer, header->common.frag_length); return rpc_recv_pdu_fragment(rpc); } else if (header->common.ptype == PTYPE_FAULT) { rpc_recv_fault_pdu(header); return -1; } rpc->VirtualConnection->DefaultOutChannel->BytesReceived += header->common.frag_length; rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow -= header->common.frag_length; #if 0 printf("BytesReceived: %d ReceiverAvailableWindow: %d ReceiveWindow: %d\n", rpc->VirtualConnection->DefaultOutChannel->BytesReceived, rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow, rpc->ReceiveWindow); #endif if (rpc->VirtualConnection->DefaultOutChannel->ReceiverAvailableWindow < (rpc->ReceiveWindow / 2)) { printf("Sending Flow Control Ack PDU\n"); rts_send_flow_control_ack_pdu(rpc); } #ifdef WITH_DEBUG_RPC rpc_pdu_header_print((rpcconn_hdr_t*) header); printf("rpc_recv_pdu_fragment: length: %d\n", header->common.frag_length); freerdp_hexdump(rpc->FragBuffer, header->common.frag_length); printf("\n"); #endif return header->common.frag_length; }