/// <summary> /// Send and receive an RPC message. /// </summary> /// <param name="proc_num">The procedure number.</param> /// <param name="objuuid">The object UUID for the call.</param> /// <param name="data_representation">NDR data representation.</param> /// <param name="ndr_buffer">Marshal NDR buffer for the call.</param> /// <param name="handles">List of handles marshaled into the buffer.</param> /// <returns>Client response from the send.</returns> public RpcClientResponse SendReceive(int proc_num, Guid objuuid, NdrDataRepresentation data_representation, byte[] ndr_buffer, IReadOnlyCollection <NtObject> handles) { NdrUnmarshalBuffer.CheckDataRepresentation(data_representation); PDURequest request = new PDURequest { OpNum = (short)proc_num, ObjectUUID = objuuid, StubData = ndr_buffer }; var recv_pdu = SendReceivePDU(request); if (recv_pdu is PDUResponse pdu_respose) { return(new RpcClientResponse(pdu_respose.StubData, new NtObject[0])); } else { throw new RpcTransportException("Unexpected PDU from server."); } }
private byte[] SendReceiveRequestPDU(int proc_num, Guid objuuid, byte[] stub_data, RpcTransportSecurityContext security_context) { try { CallId++; PDURequest request_pdu = new PDURequest() { OpNum = (short)proc_num, ObjectUUID = objuuid }; int max_fragment = _max_send_fragment - request_pdu.HeaderLength; int auth_data_length = 0; if (_auth_data_required) { auth_data_length = security_context.AuthDataLength; max_fragment -= (auth_data_length + AuthData.PDU_AUTH_DATA_HEADER_SIZE); max_fragment &= ~0xF; } List <byte[]> fragments = PDURequest.DoFragment(stub_data, max_fragment); for (int i = 0; i < fragments.Count; ++i) { PDUHeader pdu_header = new PDUHeader() { MajorVersion = PDUHeader.RPC_VERSION_MAJOR, MinorVersion = PDUHeader.RPC_VERSION_MINOR, DataRep = _data_rep, CallId = CallId, Type = PDUType.Request }; if (i == 0) { pdu_header.Flags |= PDUFlags.FirstFrag; } if (i == fragments.Count - 1) { pdu_header.Flags |= PDUFlags.LastFrag; } byte[] stub_fragment = fragments[i]; byte[] auth_data = new byte[0]; byte[] header = request_pdu.ToArray(pdu_header, stub_fragment.Length, 0); if (_auth_data_required) { int auth_data_padding = 0; int auth_trailing_size = (header.Length + stub_fragment.Length + AuthData.PDU_AUTH_DATA_HEADER_SIZE) & 0xF; if (auth_trailing_size != 0) { auth_data_padding = 16 - auth_trailing_size; Array.Resize(ref stub_fragment, stub_fragment.Length + auth_data_padding); } header = request_pdu.ToArray(pdu_header, stub_fragment.Length + AuthData.PDU_AUTH_DATA_HEADER_SIZE, auth_data_length); auth_data = security_context.ProtectPDU(header, ref stub_fragment, auth_data_padding, _send_sequence_no); } MemoryStream send_stm = new MemoryStream(); BinaryWriter writer = new BinaryWriter(send_stm); writer.Write(header); writer.Write(stub_fragment); writer.Write(auth_data); byte[] fragment = send_stm.ToArray(); string name = fragments.Count == 1 ? $"{GetType().Name} Send Buffer" : $"{GetType().Name} Send Buffer - Fragment {i}"; RpcUtils.DumpBuffer(true, name, fragment); if (!WriteFragment(fragment)) { throw new RpcTransportException("Failed to write out PDU buffer."); } _send_sequence_no++; } MemoryStream recv_stm = new MemoryStream(); PDUHeader curr_header = new PDUHeader(); int frag_count = 0; while ((curr_header.Flags & PDUFlags.LastFrag) == 0) { var pdu = ReadPDU(frag_count++); curr_header = pdu.Item1; AuthData auth_data = pdu.Item3; if (curr_header.CallId != CallId) { throw new RpcTransportException($"Mismatching call ID - {curr_header.CallId} should be {CallId}."); } if (auth_data.ContextId != security_context.ContextId) { security_context = GetContext(auth_data.ContextId); } var recv_pdu = CheckFault(curr_header.ToPDU(pdu.Item2)); if (recv_pdu is PDUResponse resp_pdu) { byte[] resp_stub_data = _auth_data_required ? security_context.UnprotectPDU(resp_pdu.ToArray(curr_header), resp_pdu.StubData, auth_data, _recv_sequence_no) : resp_pdu.StubData; _recv_sequence_no++; recv_stm.Write(resp_stub_data, 0, resp_stub_data.Length); } else { throw new RpcTransportException($"Unexpected {recv_pdu.PDUType} PDU from server."); } } return(recv_stm.ToArray()); } catch (EndOfStreamException) { throw new RpcTransportException("End of stream."); } }