DATA_BLOB recv_buffer = data_blob_null;
struct ncacn_packet *pkt;
NTSTATUS status;
- ssize_t data_left;
- ssize_t data_used;
- char *data;
uint32_t to_send;
size_t i;
bool ok;
goto fail;
}
- data_left = recv_buffer.length;
- data = (char *)recv_buffer.data;
-
- while (data_left) {
-
- data_used = process_incoming_data(npc->p, data, data_left);
- if (data_used < 0) {
- DEBUG(3, ("Failed to process dceprc request!\n"));
- status = NT_STATUS_UNEXPECTED_IO_ERROR;
- goto fail;
- }
-
- data_left -= data_used;
- data += data_used;
+ /* dcerpc_read_ncacn_packet_recv() returns a full PDU */
+ npc->p->in_data.pdu_needed_len = 0;
+ npc->p->in_data.pdu = recv_buffer;
+ if (dcerpc_get_endian_flag(&recv_buffer) & DCERPC_DREP_LE) {
+ npc->p->endian = RPC_LITTLE_ENDIAN;
+ } else {
+ npc->p->endian = RPC_BIG_ENDIAN;
}
+ DEBUG(10, ("PDU is in %s Endian format!\n",
+ npc->p->endian ? "Big" : "Little"));
+ process_complete_pdu(npc->p, pkt);
- /* Do not leak this buffer, npc is a long lived context */
+ /* reset pipe state and free PDU */
+ npc->p->in_data.pdu.length = 0;
talloc_free(recv_buffer.data);
talloc_free(pkt);
struct _output_data *out = &ncacn_conn->p->out_data;
DATA_BLOB recv_buffer = data_blob_null;
struct ncacn_packet *pkt;
- ssize_t data_left;
- ssize_t data_used;
uint32_t to_send;
- char *data;
NTSTATUS status;
bool ok;
goto fail;
}
- data_left = recv_buffer.length;
- data = (char *) recv_buffer.data;
-
- while (data_left) {
- data_used = process_incoming_data(ncacn_conn->p, data, data_left);
- if (data_used < 0) {
- DEBUG(3, ("Failed to process dcerpc request!\n"));
- status = NT_STATUS_UNEXPECTED_IO_ERROR;
- goto fail;
- }
-
- data_left -= data_used;
- data += data_used;
+ /* dcerpc_read_ncacn_packet_recv() returns a full PDU */
+ ncacn_conn->p->in_data.pdu_needed_len = 0;
+ ncacn_conn->p->in_data.pdu = recv_buffer;
+ if (dcerpc_get_endian_flag(&recv_buffer) & DCERPC_DREP_LE) {
+ ncacn_conn->p->endian = RPC_LITTLE_ENDIAN;
+ } else {
+ ncacn_conn->p->endian = RPC_BIG_ENDIAN;
}
+ DEBUG(10, ("PDU is in %s Endian format!\n",
+ ncacn_conn->p->endian ? "Big" : "Little"));
+ process_complete_pdu(ncacn_conn->p, pkt);
- /* Do not leak this buffer */
+ /* reset pipe state and free PDU */
+ ncacn_conn->p->in_data.pdu.length = 0;
talloc_free(recv_buffer.data);
talloc_free(pkt);
#undef DBGC_CLASS
#define DBGC_CLASS DBGC_RPC_SRV
-/****************************************************************************
- Ensures we have at least RPC_HEADER_LEN amount of data in the incoming buffer.
-****************************************************************************/
-
-static ssize_t fill_rpc_header(struct pipes_struct *p, const char *data, size_t data_to_copy)
-{
- size_t len_needed_to_complete_hdr =
- MIN(data_to_copy, RPC_HEADER_LEN - p->in_data.pdu.length);
-
- DEBUG(10, ("fill_rpc_header: data_to_copy = %u, "
- "len_needed_to_complete_hdr = %u, "
- "receive_len = %u\n",
- (unsigned int)data_to_copy,
- (unsigned int)len_needed_to_complete_hdr,
- (unsigned int)p->in_data.pdu.length ));
-
- if (p->in_data.pdu.data == NULL) {
- p->in_data.pdu.data = talloc_array(p, uint8_t, RPC_HEADER_LEN);
- }
- if (p->in_data.pdu.data == NULL) {
- DEBUG(0, ("talloc failed\n"));
- return -1;
- }
-
- memcpy((char *)&p->in_data.pdu.data[p->in_data.pdu.length],
- data, len_needed_to_complete_hdr);
- p->in_data.pdu.length += len_needed_to_complete_hdr;
-
- return (ssize_t)len_needed_to_complete_hdr;
-}
-
-static bool get_pdu_size(struct pipes_struct *p)
-{
- uint16_t frag_len;
- /* the fill_rpc_header() call insures we copy only
- * RPC_HEADER_LEN bytes. If this doesn't match then
- * somethign is very wrong and we can only abort */
- if (p->in_data.pdu.length != RPC_HEADER_LEN) {
- DEBUG(0, ("Unexpected RPC Header size! "
- "got %d, expected %d)\n",
- (int)p->in_data.pdu.length,
- RPC_HEADER_LEN));
- set_incoming_fault(p);
- return false;
- }
-
- frag_len = dcerpc_get_frag_length(&p->in_data.pdu);
-
- /* verify it is a reasonable value */
- if ((frag_len < RPC_HEADER_LEN) ||
- (frag_len > RPC_MAX_PDU_FRAG_LEN)) {
- DEBUG(0, ("Unexpected RPC Fragment size! (%d)\n",
- frag_len));
- set_incoming_fault(p);
- return false;
- }
-
- p->in_data.pdu_needed_len = frag_len - RPC_HEADER_LEN;
-
- /* allocate the space needed to fill the pdu */
- p->in_data.pdu.data = talloc_realloc(p, p->in_data.pdu.data,
- uint8_t, frag_len);
- if (p->in_data.pdu.data == NULL) {
- DEBUG(0, ("talloc_realloc failed\n"));
- set_incoming_fault(p);
- return false;
- }
-
- return true;
-}
-
-/****************************************************************************
- Call this to free any talloc'ed memory. Do this after processing
- a complete incoming and outgoing request (multiple incoming/outgoing
- PDU's).
-****************************************************************************/
-
-static void free_pipe_context(struct pipes_struct *p)
-{
- data_blob_free(&p->out_data.frag);
- data_blob_free(&p->out_data.rdata);
- data_blob_free(&p->in_data.data);
-
- DEBUG(3, ("free_pipe_context: "
- "destroying talloc pool of size %lu\n",
- (unsigned long)talloc_total_size(p->mem_ctx)));
- talloc_free_children(p->mem_ctx);
-}
-
-/****************************************************************************
- Accepts incoming data on an rpc pipe. Processes the data in pdu sized units.
-****************************************************************************/
-
-ssize_t process_incoming_data(struct pipes_struct *p, const char *data, size_t n)
-{
- size_t data_to_copy = MIN(n, RPC_MAX_PDU_FRAG_LEN
- - p->in_data.pdu.length);
-
- DEBUG(10, ("process_incoming_data: Start: pdu.length = %u, "
- "pdu_needed_len = %u, incoming data = %u\n",
- (unsigned int)p->in_data.pdu.length,
- (unsigned int)p->in_data.pdu_needed_len,
- (unsigned int)n ));
-
- if(data_to_copy == 0) {
- /*
- * This is an error - data is being received and there is no
- * space in the PDU. Free the received data and go into the
- * fault state.
- */
- DEBUG(0, ("process_incoming_data: "
- "No space in incoming pdu buffer. "
- "Current size = %u incoming data size = %u\n",
- (unsigned int)p->in_data.pdu.length,
- (unsigned int)n));
- set_incoming_fault(p);
- return -1;
- }
-
- /*
- * If we have no data already, wait until we get at least
- * a RPC_HEADER_LEN * number of bytes before we can do anything.
- */
-
- if ((p->in_data.pdu_needed_len == 0) &&
- (p->in_data.pdu.length < RPC_HEADER_LEN)) {
- /*
- * Always return here. If we have more data then the RPC_HEADER
- * will be processed the next time around the loop.
- */
- return fill_rpc_header(p, data, data_to_copy);
- }
-
- /*
- * At this point we know we have at least an RPC_HEADER_LEN amount of
- * data stored in p->in_data.pdu.
- */
-
- /*
- * If pdu_needed_len is zero this is a new pdu.
- * Check how much more data we need, then loop again.
- */
- if (p->in_data.pdu_needed_len == 0) {
-
- bool ok = get_pdu_size(p);
- if (!ok) {
- return -1;
- }
- if (p->in_data.pdu_needed_len > 0) {
- return 0;
- }
-
- /* If rret == 0 and pdu_needed_len == 0 here we have a PDU
- * that consists of an RPC_HEADER only. This is a
- * DCERPC_PKT_SHUTDOWN, DCERPC_PKT_CO_CANCEL or
- * DCERPC_PKT_ORPHANED pdu type.
- * Deal with this in process_complete_pdu(). */
- }
-
- /*
- * Ok - at this point we have a valid RPC_HEADER.
- * Keep reading until we have a full pdu.
- */
-
- data_to_copy = MIN(data_to_copy, p->in_data.pdu_needed_len);
-
- /*
- * Copy as much of the data as we need into the p->in_data.pdu buffer.
- * pdu_needed_len becomes zero when we have a complete pdu.
- */
-
- memcpy((char *)&p->in_data.pdu.data[p->in_data.pdu.length],
- data, data_to_copy);
- p->in_data.pdu.length += data_to_copy;
- p->in_data.pdu_needed_len -= data_to_copy;
-
- /*
- * Do we have a complete PDU ?
- * (return the number of bytes handled in the call)
- */
-
- if(p->in_data.pdu_needed_len == 0) {
- process_complete_pdu(p);
- return data_to_copy;
- }
-
- DEBUG(10, ("process_incoming_data: not a complete PDU yet. "
- "pdu.length = %u, pdu_needed_len = %u\n",
- (unsigned int)p->in_data.pdu.length,
- (unsigned int)p->in_data.pdu_needed_len));
-
- return (ssize_t)data_to_copy;
-}
-
-/****************************************************************************
- Accepts incoming data on an internal rpc pipe.
-****************************************************************************/
-
-static ssize_t write_to_internal_pipe(struct pipes_struct *p, const char *data, size_t n)
-{
- size_t data_left = n;
-
- while(data_left) {
- ssize_t data_used;
-
- DEBUG(10, ("write_to_pipe: data_left = %u\n",
- (unsigned int)data_left));
-
- data_used = process_incoming_data(p, data, data_left);
-
- DEBUG(10, ("write_to_pipe: data_used = %d\n",
- (int)data_used));
-
- if(data_used < 0) {
- return -1;
- }
-
- data_left -= data_used;
- data += data_used;
- }
-
- return n;
-}
-
-/****************************************************************************
- Replies to a request to read data from a pipe.
-
- Headers are interspersed with the data at PDU intervals. By the time
- this function is called, the start of the data could possibly have been
- read by an SMBtrans (file_offset != 0).
-
- Calling create_rpc_reply() here is a hack. The data should already
- have been prepared into arrays of headers + data stream sections.
-****************************************************************************/
-
-static ssize_t read_from_internal_pipe(struct pipes_struct *p, char *data,
- size_t n, bool *is_data_outstanding)
-{
- uint32 pdu_remaining = 0;
- ssize_t data_returned = 0;
-
- if (!p) {
- DEBUG(0,("read_from_pipe: pipe not open\n"));
- return -1;
- }
-
- DEBUG(6,(" name: %s len: %u\n",
- ndr_interface_name(&p->contexts->syntax.uuid,
- p->contexts->syntax.if_version),
- (unsigned int)n));
-
- /*
- * We cannot return more than one PDU length per
- * read request.
- */
-
- /*
- * This condition should result in the connection being closed.
- * Netapp filers seem to set it to 0xffff which results in domain
- * authentications failing. Just ignore it so things work.
- */
-
- if(n > RPC_MAX_PDU_FRAG_LEN) {
- DEBUG(5,("read_from_pipe: too large read (%u) requested on "
- "pipe %s. We can only service %d sized reads.\n",
- (unsigned int)n,
- ndr_interface_name(&p->contexts->syntax.uuid,
- p->contexts->syntax.if_version),
- RPC_MAX_PDU_FRAG_LEN ));
- n = RPC_MAX_PDU_FRAG_LEN;
- }
-
- /*
- * Determine if there is still data to send in the
- * pipe PDU buffer. Always send this first. Never
- * send more than is left in the current PDU. The
- * client should send a new read request for a new
- * PDU.
- */
-
- pdu_remaining = p->out_data.frag.length
- - p->out_data.current_pdu_sent;
-
- if (pdu_remaining > 0) {
- data_returned = (ssize_t)MIN(n, pdu_remaining);
-
- DEBUG(10,("read_from_pipe: %s: current_pdu_len = %u, "
- "current_pdu_sent = %u returning %d bytes.\n",
- ndr_interface_name(&p->contexts->syntax.uuid,
- p->contexts->syntax.if_version),
- (unsigned int)p->out_data.frag.length,
- (unsigned int)p->out_data.current_pdu_sent,
- (int)data_returned));
-
- memcpy(data,
- p->out_data.frag.data
- + p->out_data.current_pdu_sent,
- data_returned);
-
- p->out_data.current_pdu_sent += (uint32)data_returned;
- goto out;
- }
-
- /*
- * At this point p->current_pdu_len == p->current_pdu_sent (which
- * may of course be zero if this is the first return fragment.
- */
-
- DEBUG(10,("read_from_pipe: %s: fault_state = %d : data_sent_length "
- "= %u, p->out_data.rdata.length = %u.\n",
- ndr_interface_name(&p->contexts->syntax.uuid,
- p->contexts->syntax.if_version),
- (int)p->fault_state,
- (unsigned int)p->out_data.data_sent_length,
- (unsigned int)p->out_data.rdata.length));
-
- if (p->out_data.data_sent_length >= p->out_data.rdata.length) {
- /*
- * We have sent all possible data, return 0.
- */
- data_returned = 0;
- goto out;
- }
-
- /*
- * We need to create a new PDU from the data left in p->rdata.
- * Create the header/data/footers. This also sets up the fields
- * p->current_pdu_len, p->current_pdu_sent, p->data_sent_length
- * and stores the outgoing PDU in p->current_pdu.
- */
-
- if(!create_next_pdu(p)) {
- DEBUG(0,("read_from_pipe: %s: create_next_pdu failed.\n",
- ndr_interface_name(&p->contexts->syntax.uuid,
- p->contexts->syntax.if_version)));
- return -1;
- }
-
- data_returned = MIN(n, p->out_data.frag.length);
-
- memcpy(data, p->out_data.frag.data, (size_t)data_returned);
- p->out_data.current_pdu_sent += (uint32)data_returned;
-
- out:
- (*is_data_outstanding) = p->out_data.frag.length > n;
-
- if (p->out_data.current_pdu_sent == p->out_data.frag.length) {
- /* We've returned everything in the out_data.frag
- * so we're done with this pdu. Free it and reset
- * current_pdu_sent. */
- p->out_data.current_pdu_sent = 0;
- data_blob_free(&p->out_data.frag);
-
- if (p->out_data.data_sent_length >= p->out_data.rdata.length) {
- /*
- * We're completely finished with both outgoing and
- * incoming data streams. It's safe to free all
- * temporary data from this request.
- */
- free_pipe_context(p);
- }
- }
-
- return data_returned;
-}
-
bool fsp_is_np(struct files_struct *fsp)
{
enum FAKE_FILE_TYPE type;