X-Git-Url: http://git.samba.org/samba.git/?a=blobdiff_plain;f=source3%2Frpc_server%2Fsrv_pipe_hnd.c;h=fb7aca5c0fa2febbf9f3578d72962ce41f2dd3d3;hb=fe486d7b9f580a17d23dd57582087c7d28cb738d;hp=d359b9b339e7722a811da84228d44252119c3fb5;hpb=ace87f16c0f75d5d7685f3b4f187be539ca8ede4;p=ira%2Fwip.git diff --git a/source3/rpc_server/srv_pipe_hnd.c b/source3/rpc_server/srv_pipe_hnd.c index d359b9b339e..fb7aca5c0fa 100644 --- a/source3/rpc_server/srv_pipe_hnd.c +++ b/source3/rpc_server/srv_pipe_hnd.c @@ -28,7 +28,6 @@ static int pipes_open; static pipes_struct *InternalPipes; -static struct bitmap *bmap; /* TODO * the following prototypes are declared here to avoid @@ -56,18 +55,6 @@ pipes_struct *get_next_internal_pipe(pipes_struct *p) return p->next; } -/**************************************************************************** - Initialise pipe handle states. -****************************************************************************/ - -void init_rpc_pipe_hnd(void) -{ - bmap = bitmap_allocate(MAX_OPEN_PIPES); - if (!bmap) { - exit_server("out of memory in init_rpc_pipe_hnd"); - } -} - /**************************************************************************** Initialise an outgoing packet. ****************************************************************************/ @@ -78,10 +65,9 @@ static bool pipe_init_outgoing_data(pipes_struct *p) /* Reset the offset counters. */ o_data->data_sent_length = 0; - o_data->current_pdu_len = 0; o_data->current_pdu_sent = 0; - memset(o_data->current_pdu, '\0', sizeof(o_data->current_pdu)); + prs_mem_free(&o_data->frag); /* Free any memory in the current return data buffer. */ prs_mem_free(&o_data->rdata); @@ -90,7 +76,7 @@ static bool pipe_init_outgoing_data(pipes_struct *p) * Initialize the outgoing RPC data buffer. * we will use this as the raw data area for replying to rpc requests. */ - if(!prs_init(&o_data->rdata, RPC_MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) { + if(!prs_init(&o_data->rdata, 128, p->mem_ctx, MARSHALL)) { DEBUG(0,("pipe_init_outgoing_data: malloc fail.\n")); return False; } @@ -103,14 +89,14 @@ static bool pipe_init_outgoing_data(pipes_struct *p) ****************************************************************************/ static struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx, - const char *pipe_name, + const struct ndr_syntax_id *syntax, const char *client_address, - struct auth_serversupplied_info *server_info, - uint16_t vuid) + struct auth_serversupplied_info *server_info) { pipes_struct *p; - DEBUG(4,("Create pipe requested %s\n", pipe_name)); + DEBUG(4,("Create pipe requested %s\n", + get_pipe_name_from_iface(syntax))); p = TALLOC_ZERO_P(mem_ctx, struct pipes_struct); @@ -119,13 +105,15 @@ static struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx, return NULL; } - if ((p->mem_ctx = talloc_init("pipe %s %p", pipe_name, p)) == NULL) { + if ((p->mem_ctx = talloc_init("pipe %s %p", + get_pipe_name_from_iface(syntax), + p)) == NULL) { DEBUG(0,("open_rpc_pipe_p: talloc_init failed.\n")); TALLOC_FREE(p); return NULL; } - if (!init_pipe_handle_list(p, pipe_name)) { + if (!init_pipe_handle_list(p, syntax)) { DEBUG(0,("open_rpc_pipe_p: init_pipe_handles failed.\n")); talloc_destroy(p->mem_ctx); TALLOC_FREE(p); @@ -139,7 +127,7 @@ static struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx, * change the type to UNMARSALLING before processing the stream. */ - if(!prs_init(&p->in_data.data, RPC_MAX_PDU_FRAG_LEN, p->mem_ctx, MARSHALL)) { + if(!prs_init(&p->in_data.data, 128, p->mem_ctx, MARSHALL)) { DEBUG(0,("open_rpc_pipe_p: malloc fail for in_data struct.\n")); talloc_destroy(p->mem_ctx); close_policy_by_pipe(p); @@ -162,22 +150,15 @@ static struct pipes_struct *make_internal_rpc_pipe_p(TALLOC_CTX *mem_ctx, p->endian = RPC_LITTLE_ENDIAN; - ZERO_STRUCT(p->pipe_user); - - p->pipe_user.vuid = vuid; - p->pipe_user.ut.uid = (uid_t)-1; - p->pipe_user.ut.gid = (gid_t)-1; - p->pipe_user.nt_user_token = dup_nt_token(NULL, server_info->ptok); - /* * Initialize the outgoing RPC data buffer with no memory. */ prs_init_empty(&p->out_data.rdata, p->mem_ctx, MARSHALL); - - fstrcpy(p->name, pipe_name); - + + p->syntax = *syntax; + DEBUG(4,("Created internal pipe %s (pipes_open=%d)\n", - pipe_name, pipes_open)); + get_pipe_name_from_iface(syntax), pipes_open)); talloc_set_destructor(p, close_internal_rpc_pipe_hnd); @@ -195,7 +176,7 @@ static void set_incoming_fault(pipes_struct *p) p->in_data.pdu_received_len = 0; p->fault_state = True; DEBUG(10, ("set_incoming_fault: Setting fault state on pipe %s\n", - p->name)); + get_pipe_name_from_iface(&p->syntax))); } /**************************************************************************** @@ -210,6 +191,15 @@ static ssize_t fill_rpc_header(pipes_struct *p, char *data, size_t data_to_copy) (unsigned int)data_to_copy, (unsigned int)len_needed_to_complete_hdr, (unsigned int)p->in_data.pdu_received_len )); + if (p->in_data.current_in_pdu == NULL) { + p->in_data.current_in_pdu = talloc_array(p, uint8_t, + RPC_HEADER_LEN); + } + if (p->in_data.current_in_pdu == NULL) { + DEBUG(0, ("talloc failed\n")); + return -1; + } + memcpy((char *)&p->in_data.current_in_pdu[p->in_data.pdu_received_len], data, len_needed_to_complete_hdr); p->in_data.pdu_received_len += len_needed_to_complete_hdr; @@ -330,6 +320,14 @@ static ssize_t unmarshall_rpc_header(pipes_struct *p) prs_mem_free(&rpc_in); + p->in_data.current_in_pdu = TALLOC_REALLOC_ARRAY( + p, p->in_data.current_in_pdu, uint8_t, p->hdr.frag_len); + if (p->in_data.current_in_pdu == NULL) { + DEBUG(0, ("talloc failed\n")); + set_incoming_fault(p); + return -1; + } + return 0; /* No extra data processed. */ } @@ -345,7 +343,8 @@ static void free_pipe_context(pipes_struct *p) "%lu\n", (unsigned long)talloc_total_size(p->mem_ctx) )); talloc_free_children(p->mem_ctx); } else { - p->mem_ctx = talloc_init("pipe %s %p", p->name, p); + p->mem_ctx = talloc_init( + "pipe %s %p", get_pipe_name_from_iface(&p->syntax), p); if (p->mem_ctx == NULL) { p->fault_state = True; } @@ -427,7 +426,7 @@ static bool process_request_pdu(pipes_struct *p, prs_struct *rpc_in_p) * will not fit in the initial buffer of size 0x1068 --jerry 22/01/2002 */ - if(prs_offset(&p->in_data.data) + data_len > 15*1024*1024) { + if(prs_offset(&p->in_data.data) + data_len > MAX_RPC_DATA_SIZE) { DEBUG(0,("process_request_pdu: rpc data buffer too large (%u) + (%u)\n", (unsigned int)prs_data_size(&p->in_data.data), (unsigned int)data_len )); set_incoming_fault(p); @@ -513,7 +512,7 @@ static void process_complete_pdu(pipes_struct *p) if(p->fault_state) { DEBUG(10,("process_complete_pdu: pipe %s in fault state.\n", - p->name )); + get_pipe_name_from_iface(&p->syntax))); set_incoming_fault(p); setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR)); return; @@ -541,12 +540,13 @@ static void process_complete_pdu(pipes_struct *p) case RPC_PING: /* CL request - ignore... */ DEBUG(0,("process_complete_pdu: Error. Connectionless packet type %u received on pipe %s.\n", - (unsigned int)p->hdr.pkt_type, p->name)); + (unsigned int)p->hdr.pkt_type, + get_pipe_name_from_iface(&p->syntax))); break; case RPC_RESPONSE: /* No responses here. */ DEBUG(0,("process_complete_pdu: Error. RPC_RESPONSE received from client on pipe %s.\n", - p->name )); + get_pipe_name_from_iface(&p->syntax))); break; case RPC_FAULT: @@ -558,7 +558,8 @@ static void process_complete_pdu(pipes_struct *p) case RPC_FACK: case RPC_CANCEL_ACK: DEBUG(0,("process_complete_pdu: Error. Connectionless packet type %u received on pipe %s.\n", - (unsigned int)p->hdr.pkt_type, p->name)); + (unsigned int)p->hdr.pkt_type, + get_pipe_name_from_iface(&p->syntax))); break; case RPC_BIND: @@ -573,7 +574,8 @@ static void process_complete_pdu(pipes_struct *p) case RPC_BINDACK: case RPC_BINDNACK: DEBUG(0,("process_complete_pdu: Error. RPC_BINDACK/RPC_BINDNACK packet type %u received on pipe %s.\n", - (unsigned int)p->hdr.pkt_type, p->name)); + (unsigned int)p->hdr.pkt_type, + get_pipe_name_from_iface(&p->syntax))); break; @@ -588,7 +590,7 @@ static void process_complete_pdu(pipes_struct *p) case RPC_ALTCONTRESP: DEBUG(0,("process_complete_pdu: Error. RPC_ALTCONTRESP on pipe %s: Should only be server -> client.\n", - p->name)); + get_pipe_name_from_iface(&p->syntax))); break; case RPC_AUTH3: @@ -602,7 +604,7 @@ static void process_complete_pdu(pipes_struct *p) case RPC_SHUTDOWN: DEBUG(0,("process_complete_pdu: Error. RPC_SHUTDOWN on pipe %s: Should only be server -> client.\n", - p->name)); + get_pipe_name_from_iface(&p->syntax))); break; case RPC_CO_CANCEL: @@ -640,7 +642,8 @@ static void process_complete_pdu(pipes_struct *p) prs_set_endian_data( &p->in_data.data, RPC_LITTLE_ENDIAN); if (!reply) { - DEBUG(3,("process_complete_pdu: DCE/RPC fault sent on pipe %s\n", p->pipe_srv_name)); + DEBUG(3,("process_complete_pdu: DCE/RPC fault sent on " + "pipe %s\n", get_pipe_name_from_iface(&p->syntax))); set_incoming_fault(p); setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR)); prs_mem_free(&rpc_in); @@ -648,6 +651,7 @@ static void process_complete_pdu(pipes_struct *p) /* * Reset the lengths. We're ready for a new pdu. */ + TALLOC_FREE(p->in_data.current_in_pdu); p->in_data.pdu_needed_len = 0; p->in_data.pdu_received_len = 0; } @@ -794,7 +798,8 @@ static ssize_t read_from_internal_pipe(struct pipes_struct *p, char *data, size_ return -1; } - DEBUG(6,(" name: %s len: %u\n", p->name, (unsigned int)n)); + DEBUG(6,(" name: %s len: %u\n", get_pipe_name_from_iface(&p->syntax), + (unsigned int)n)); /* * We cannot return more than one PDU length per @@ -808,8 +813,10 @@ static ssize_t read_from_internal_pipe(struct pipes_struct *p, char *data, size_ */ 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, p->name, 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, get_pipe_name_from_iface(&p->syntax), + RPC_MAX_PDU_FRAG_LEN )); n = RPC_MAX_PDU_FRAG_LEN; } @@ -821,14 +828,24 @@ pipe %s. We can only service %d sized reads.\n", (unsigned int)n, p->name, RPC_M * PDU. */ - if((pdu_remaining = p->out_data.current_pdu_len - p->out_data.current_pdu_sent) > 0) { + pdu_remaining = prs_offset(&p->out_data.frag) + - 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", p->name, (unsigned int)p->out_data.current_pdu_len, - (unsigned int)p->out_data.current_pdu_sent, (int)data_returned)); + DEBUG(10,("read_from_pipe: %s: current_pdu_len = %u, " + "current_pdu_sent = %u returning %d bytes.\n", + get_pipe_name_from_iface(&p->syntax), + (unsigned int)prs_offset(&p->out_data.frag), + (unsigned int)p->out_data.current_pdu_sent, + (int)data_returned)); + + memcpy(data, + prs_data_p(&p->out_data.frag) + + p->out_data.current_pdu_sent, + data_returned); - memcpy( data, &p->out_data.current_pdu[p->out_data.current_pdu_sent], (size_t)data_returned); p->out_data.current_pdu_sent += (uint32)data_returned; goto out; } @@ -838,9 +855,11 @@ returning %d bytes.\n", p->name, (unsigned int)p->out_data.current_pdu_len, * 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, prs_offset(&p->out_data.rdata) = %u.\n", - p->name, (int)p->fault_state, (unsigned int)p->out_data.data_sent_length, (unsigned int)prs_offset(&p->out_data.rdata) )); + DEBUG(10,("read_from_pipe: %s: fault_state = %d : data_sent_length " + "= %u, prs_offset(&p->out_data.rdata) = %u.\n", + get_pipe_name_from_iface(&p->syntax), (int)p->fault_state, + (unsigned int)p->out_data.data_sent_length, + (unsigned int)prs_offset(&p->out_data.rdata) )); if(p->out_data.data_sent_length >= prs_offset(&p->out_data.rdata)) { /* @@ -858,18 +877,19 @@ returning %d bytes.\n", p->name, (unsigned int)p->out_data.current_pdu_len, */ if(!create_next_pdu(p)) { - DEBUG(0,("read_from_pipe: %s: create_next_pdu failed.\n", p->name)); + DEBUG(0,("read_from_pipe: %s: create_next_pdu failed.\n", + get_pipe_name_from_iface(&p->syntax))); return -1; } - data_returned = MIN(n, p->out_data.current_pdu_len); + data_returned = MIN(n, prs_offset(&p->out_data.frag)); - memcpy( data, p->out_data.current_pdu, (size_t)data_returned); + memcpy( data, prs_data_p(&p->out_data.frag), (size_t)data_returned); p->out_data.current_pdu_sent += (uint32)data_returned; out: + (*is_data_outstanding) = prs_offset(&p->out_data.frag) > n; - (*is_data_outstanding) = p->out_data.current_pdu_len > n; return data_returned; } @@ -884,6 +904,7 @@ static int close_internal_rpc_pipe_hnd(struct pipes_struct *p) return False; } + prs_mem_free(&p->out_data.frag); prs_mem_free(&p->out_data.rdata); prs_mem_free(&p->in_data.data); @@ -891,18 +912,13 @@ static int close_internal_rpc_pipe_hnd(struct pipes_struct *p) (*p->auth.auth_data_free_func)(&p->auth); } - if (p->mem_ctx) { - talloc_destroy(p->mem_ctx); - } + TALLOC_FREE(p->mem_ctx); free_pipe_rpc_context( p->contexts ); /* Free the handles database. */ close_policy_by_pipe(p); - TALLOC_FREE(p->pipe_user.nt_user_token); - SAFE_FREE(p->pipe_user.ut.groups); - DLIST_REMOVE(InternalPipes, p); ZERO_STRUCTP(p); @@ -927,7 +943,12 @@ bool fsp_is_np(struct files_struct *fsp) } struct np_proxy_state { + struct async_req_queue *read_queue; + struct async_req_queue *write_queue; int fd; + + uint8_t *msg; + size_t sent; }; static int np_proxy_state_destructor(struct np_proxy_state *state) @@ -1081,6 +1102,17 @@ static struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx, goto fail; } + result->msg = NULL; + + result->read_queue = async_req_queue_init(result); + if (result->read_queue == NULL) { + goto fail; + } + result->write_queue = async_req_queue_init(result); + if (result->write_queue == NULL) { + goto fail; + } + return result; fail: @@ -1088,142 +1120,369 @@ static struct np_proxy_state *make_external_rpc_pipe_p(TALLOC_CTX *mem_ctx, return NULL; } -NTSTATUS np_open(struct smb_request *smb_req, struct connection_struct *conn, - const char *name, struct files_struct **pfsp) +NTSTATUS np_open(TALLOC_CTX *mem_ctx, const char *name, + const char *client_address, + struct auth_serversupplied_info *server_info, + struct fake_file_handle **phandle) { - NTSTATUS status; - struct files_struct *fsp; const char **proxy_list; + struct fake_file_handle *handle; - proxy_list = lp_parm_string_list(SNUM(conn), "np", "proxy", NULL); + proxy_list = lp_parm_string_list(-1, "np", "proxy", NULL); - status = file_new(smb_req, conn, &fsp); - if (!NT_STATUS_IS_OK(status)) { - DEBUG(0, ("file_new failed: %s\n", nt_errstr(status))); - return status; - } - - fsp->conn = conn; - fsp->fh->fd = -1; - fsp->vuid = smb_req->vuid; - fsp->can_lock = false; - fsp->access_mask = FILE_READ_DATA | FILE_WRITE_DATA; - string_set(&fsp->fsp_name, name); - - fsp->fake_file_handle = talloc(NULL, struct fake_file_handle); - if (fsp->fake_file_handle == NULL) { - file_free(smb_req, fsp); + handle = talloc(mem_ctx, struct fake_file_handle); + if (handle == NULL) { return NT_STATUS_NO_MEMORY; } if ((proxy_list != NULL) && str_list_check_ci(proxy_list, name)) { struct np_proxy_state *p; - p = make_external_rpc_pipe_p(fsp->fake_file_handle, name, - conn->server_info); + p = make_external_rpc_pipe_p(handle, name, server_info); - fsp->fake_file_handle->type = FAKE_FILE_TYPE_NAMED_PIPE_PROXY; - fsp->fake_file_handle->private_data = p; + handle->type = FAKE_FILE_TYPE_NAMED_PIPE_PROXY; + handle->private_data = p; } else { struct pipes_struct *p; + struct ndr_syntax_id syntax; - if (!is_known_pipename(name)) { - file_free(smb_req, fsp); + if (!is_known_pipename(name, &syntax)) { + TALLOC_FREE(handle); return NT_STATUS_OBJECT_NAME_NOT_FOUND; } - p = make_internal_rpc_pipe_p(fsp->fake_file_handle, name, - conn->client_address, - conn->server_info, - smb_req->vuid); + p = make_internal_rpc_pipe_p(handle, &syntax, client_address, + server_info); - fsp->fake_file_handle->type = FAKE_FILE_TYPE_NAMED_PIPE; - fsp->fake_file_handle->private_data = p; + handle->type = FAKE_FILE_TYPE_NAMED_PIPE; + handle->private_data = p; } - if (fsp->fake_file_handle->private_data == NULL) { - file_free(smb_req, fsp); + if (handle->private_data == NULL) { + TALLOC_FREE(handle); return NT_STATUS_PIPE_NOT_AVAILABLE; } - *pfsp = fsp; + *phandle = handle; return NT_STATUS_OK; } -NTSTATUS np_write(struct files_struct *fsp, const uint8_t *data, size_t len, - ssize_t *nwritten) +struct np_write_state { + struct event_context *ev; + struct np_proxy_state *p; + struct iovec iov; + ssize_t nwritten; +}; + +static void np_write_trigger(struct async_req *req); +static void np_write_done(struct tevent_req *subreq); + +struct async_req *np_write_send(TALLOC_CTX *mem_ctx, struct event_context *ev, + struct fake_file_handle *handle, + const uint8_t *data, size_t len) { - if (!fsp_is_np(fsp)) { - return NT_STATUS_INVALID_HANDLE; - } + struct async_req *result; + struct np_write_state *state; + NTSTATUS status; - DEBUG(6, ("np_write: %x name: %s len: %d\n", (int)fsp->fnum, - fsp->fsp_name, (int)len)); + DEBUG(6, ("np_write_send: len: %d\n", (int)len)); dump_data(50, data, len); - switch (fsp->fake_file_handle->type) { - case FAKE_FILE_TYPE_NAMED_PIPE: { + if (!async_req_setup(mem_ctx, &result, &state, + struct np_write_state)) { + return NULL; + } + + if (len == 0) { + state->nwritten = 0; + status = NT_STATUS_OK; + goto post_status; + } + + if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE) { struct pipes_struct *p = talloc_get_type_abort( - fsp->fake_file_handle->private_data, - struct pipes_struct); - *nwritten = write_to_internal_pipe(p, (char *)data, len); - break; + handle->private_data, struct pipes_struct); + + state->nwritten = write_to_internal_pipe(p, (char *)data, len); + + status = (state->nwritten >= 0) + ? NT_STATUS_OK : NT_STATUS_UNEXPECTED_IO_ERROR; + goto post_status; } - case FAKE_FILE_TYPE_NAMED_PIPE_PROXY: { + + if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) { struct np_proxy_state *p = talloc_get_type_abort( - fsp->fake_file_handle->private_data, - struct np_proxy_state); - *nwritten = write_data(p->fd, (char *)data, len); - break; + handle->private_data, struct np_proxy_state); + + state->ev = ev; + state->p = p; + state->iov.iov_base = CONST_DISCARD(void *, data); + state->iov.iov_len = len; + + if (!async_req_enqueue(p->write_queue, ev, result, + np_write_trigger)) { + goto fail; + } + return result; + } + + status = NT_STATUS_INVALID_HANDLE; + post_status: + if (async_post_ntstatus(result, ev, status)) { + return result; + } + fail: + TALLOC_FREE(result); + return NULL; +} + +static void np_write_trigger(struct async_req *req) +{ + struct np_write_state *state = talloc_get_type_abort( + req->private_data, struct np_write_state); + struct tevent_req *subreq; + + subreq = writev_send(state, state->ev, NULL, state->p->fd, + &state->iov, 1); + if (async_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, np_write_done, req); +} + +static void np_write_done(struct tevent_req *subreq) +{ + struct async_req *req = + tevent_req_callback_data(subreq, struct async_req); + struct np_write_state *state = talloc_get_type_abort( + req->private_data, struct np_write_state); + ssize_t received; + int err; + + received = writev_recv(subreq, &err); + if (received < 0) { + async_req_nterror(req, map_nt_error_from_unix(err)); + return; + } + state->nwritten = received; + async_req_done(req); +} + +NTSTATUS np_write_recv(struct async_req *req, ssize_t *pnwritten) +{ + struct np_write_state *state = talloc_get_type_abort( + req->private_data, struct np_write_state); + NTSTATUS status; + + if (async_req_is_nterror(req, &status)) { + return status; } - default: - return NT_STATUS_INVALID_HANDLE; - break; + *pnwritten = state->nwritten; + return NT_STATUS_OK; +} + +static ssize_t rpc_frag_more_fn(uint8_t *buf, size_t buflen, void *priv) +{ + prs_struct hdr_prs; + struct rpc_hdr_info hdr; + bool ret; + + if (buflen > RPC_HEADER_LEN) { + return 0; } + prs_init_empty(&hdr_prs, talloc_tos(), UNMARSHALL); + prs_give_memory(&hdr_prs, (char *)buf, RPC_HEADER_LEN, false); + ret = smb_io_rpc_hdr("", &hdr, &hdr_prs, 0); + prs_mem_free(&hdr_prs); - return ((*nwritten) >= 0) - ? NT_STATUS_OK : NT_STATUS_UNEXPECTED_IO_ERROR; + if (!ret) { + return -1; + } + + return (hdr.frag_len - RPC_HEADER_LEN); } -NTSTATUS np_read(struct files_struct *fsp, uint8_t *data, size_t len, - ssize_t *nread, bool *is_data_outstanding) +struct np_read_state { + struct event_context *ev; + struct np_proxy_state *p; + uint8_t *data; + size_t len; + + size_t nread; + bool is_data_outstanding; +}; + +static void np_read_trigger(struct async_req *req); +static void np_read_done(struct tevent_req *subreq); + +struct async_req *np_read_send(TALLOC_CTX *mem_ctx, struct event_context *ev, + struct fake_file_handle *handle, + uint8_t *data, size_t len) { - if (!fsp_is_np(fsp)) { - return NT_STATUS_INVALID_HANDLE; + struct async_req *result; + struct np_read_state *state; + NTSTATUS status; + + if (!async_req_setup(mem_ctx, &result, &state, + struct np_read_state)) { + return NULL; } - switch (fsp->fake_file_handle->type) { - case FAKE_FILE_TYPE_NAMED_PIPE: { + if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE) { struct pipes_struct *p = talloc_get_type_abort( - fsp->fake_file_handle->private_data, - struct pipes_struct); - *nread = read_from_internal_pipe(p, (char *)data, len, - is_data_outstanding); - break; + handle->private_data, struct pipes_struct); + + state->nread = read_from_internal_pipe( + p, (char *)data, len, &state->is_data_outstanding); + + status = (state->nread >= 0) + ? NT_STATUS_OK : NT_STATUS_UNEXPECTED_IO_ERROR; + goto post_status; } - case FAKE_FILE_TYPE_NAMED_PIPE_PROXY: { + + if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) { struct np_proxy_state *p = talloc_get_type_abort( - fsp->fake_file_handle->private_data, - struct np_proxy_state); - int available = 0; + handle->private_data, struct np_proxy_state); - *nread = sys_read(p->fd, (char *)data, len); + if (p->msg != NULL) { + size_t thistime; - /* - * We don't look at the ioctl result. We don't really care - * if there is data available, because this is racy anyway. - */ - ioctl(p->fd, FIONREAD, &available); - *is_data_outstanding = (available > 0); + thistime = MIN(talloc_get_size(p->msg) - p->sent, + len); + + memcpy(data, p->msg+p->sent, thistime); + state->nread = thistime; + p->sent += thistime; - break; + if (p->sent < talloc_get_size(p->msg)) { + state->is_data_outstanding = true; + } else { + state->is_data_outstanding = false; + TALLOC_FREE(p->msg); + } + status = NT_STATUS_OK; + goto post_status; + } + + state->ev = ev; + state->p = p; + state->data = data; + state->len = len; + + if (!async_req_enqueue(p->read_queue, ev, result, + np_read_trigger)) { + goto fail; + } + return result; } - default: - return NT_STATUS_INVALID_HANDLE; - break; + + status = NT_STATUS_INVALID_HANDLE; + post_status: + if (async_post_ntstatus(result, ev, status)) { + return result; } + fail: + TALLOC_FREE(result); + return NULL; +} - return ((*nread) >= 0) - ? NT_STATUS_OK : NT_STATUS_UNEXPECTED_IO_ERROR; +static void np_read_trigger(struct async_req *req) +{ + struct np_read_state *state = talloc_get_type_abort( + req->private_data, struct np_read_state); + struct tevent_req *subreq; + + subreq = read_packet_send(state, state->ev, state->p->fd, + RPC_HEADER_LEN, rpc_frag_more_fn, NULL); + if (async_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, np_read_done, req); +} + +static void np_read_done(struct tevent_req *subreq) +{ + struct async_req *req = + tevent_req_callback_data(subreq, struct async_req); + struct np_read_state *state = talloc_get_type_abort( + req->private_data, struct np_read_state); + ssize_t received; + size_t thistime; + int err; + + received = read_packet_recv(subreq, state->p, &state->p->msg, &err); + TALLOC_FREE(subreq); + if (received == -1) { + async_req_nterror(req, map_nt_error_from_unix(err)); + return; + } + + thistime = MIN(received, state->len); + + memcpy(state->data, state->p->msg, thistime); + state->p->sent = thistime; + state->nread = thistime; + + if (state->p->sent < received) { + state->is_data_outstanding = true; + } else { + TALLOC_FREE(state->p->msg); + state->is_data_outstanding = false; + } + + async_req_done(req); + return; +} + +NTSTATUS np_read_recv(struct async_req *req, ssize_t *nread, + bool *is_data_outstanding) +{ + struct np_read_state *state = talloc_get_type_abort( + req->private_data, struct np_read_state); + NTSTATUS status; + + if (async_req_is_nterror(req, &status)) { + return status; + } + *nread = state->nread; + *is_data_outstanding = state->is_data_outstanding; + return NT_STATUS_OK; +} + +/** + * Create a new RPC client context which uses a local dispatch function. + */ +NTSTATUS rpc_pipe_open_internal(TALLOC_CTX *mem_ctx, + const struct ndr_syntax_id *abstract_syntax, + NTSTATUS (*dispatch) (struct rpc_pipe_client *cli, + TALLOC_CTX *mem_ctx, + const struct ndr_interface_table *table, + uint32_t opnum, void *r), + struct auth_serversupplied_info *serversupplied_info, + struct rpc_pipe_client **presult) +{ + struct rpc_pipe_client *result; + + result = TALLOC_ZERO_P(mem_ctx, struct rpc_pipe_client); + if (result == NULL) { + return NT_STATUS_NO_MEMORY; + } + + result->abstract_syntax = *abstract_syntax; + result->transfer_syntax = ndr_transfer_syntax; + result->dispatch = dispatch; + + result->pipes_struct = make_internal_rpc_pipe_p( + result, abstract_syntax, "", serversupplied_info); + if (result->pipes_struct == NULL) { + TALLOC_FREE(result); + return NT_STATUS_NO_MEMORY; + } + + result->max_xmit_frag = -1; + result->max_recv_frag = -1; + + *presult = result; + return NT_STATUS_OK; }