Exemple #1
0
        /// <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.");
            }
        }