}
static void named_pipe_packet_process(struct tevent_req *subreq);
+static void named_pipe_packet_respond(struct tevent_req *subreq);
static void named_pipe_packet_done(struct tevent_req *subreq);
static void named_pipe_accept_done(struct tevent_req *subreq)
{
struct named_pipe_client *npc =
tevent_req_callback_data(subreq, struct named_pipe_client);
- struct _output_data *out = &npc->p->out_data;
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;
status = dcerpc_read_ncacn_packet_recv(subreq, npc, &pkt, &recv_buffer);
TALLOC_FREE(subreq);
data += data_used;
if (pdu_ready == true) {
- process_complete_pdu(npc->p);
- break;
+ /* XXX received PDUs are processed one at a time */
+ if (data_left > 0) {
+ DEBUG(0, ("Unacceptable, more than one PDU\n"));
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+ /* Do not leak this buffer, npc is a long lived context */
+ talloc_free(recv_buffer.data);
+ talloc_free(pkt);
+
+ subreq = process_complete_pdu_send(npc->ev, npc->p);
+ if (subreq == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq,
+ named_pipe_packet_respond,
+ npc);
+ return;
}
}
+ DEBUG(0, ("No complete PDU to process\n"));
+
/* Do not leak this buffer, npc is a long lived context */
talloc_free(recv_buffer.data);
talloc_free(pkt);
+ /* Wait for the next packet */
+ subreq = dcerpc_read_ncacn_packet_send(npc, npc->ev, npc->tstream);
+ if (!subreq) {
+ DEBUG(2, ("Failed to start receving packets\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, named_pipe_packet_process, npc);
+ return;
+
+fail:
+ DEBUG(2, ("Fatal error(%s). "
+ "Terminating client(%s) connection!\n",
+ nt_errstr(status), npc->client_name));
+ /* terminate client connection */
+ talloc_free(npc);
+ return;
+}
+
+static void named_pipe_packet_respond(struct tevent_req *subreq)
+{
+ struct named_pipe_client *npc =
+ tevent_req_callback_data(subreq, struct named_pipe_client);
+ uint32_t to_send;
+ size_t i;
+ bool ok;
+ struct _output_data *out;
+ NTSTATUS status;
+
+ process_complete_pdu_recv(subreq);
+ TALLOC_FREE(subreq);
+
+ out = &npc->p->out_data;
/* this is needed because of the way DCERPC Binds work in
* the RPC marshalling code */
to_send = out->frag.length - out->current_pdu_sent;
};
static void dcerpc_ncacn_packet_process(struct tevent_req *subreq);
+static void dcerpc_ncacn_packet_respond(struct tevent_req *subreq);
static void dcerpc_ncacn_packet_done(struct tevent_req *subreq);
void dcerpc_ncacn_accept(struct tevent_context *ev_ctx,
struct dcerpc_ncacn_conn *ncacn_conn =
tevent_req_callback_data(subreq, struct dcerpc_ncacn_conn);
- 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;
data += data_used;
if (pdu_ready == true) {
- process_complete_pdu(ncacn_conn->p);
- break;
+ /* XXX received PDUs are processed one at a time */
+ if (data_left > 0) {
+ DEBUG(0, ("Unacceptable, more than one PDU\n"));
+ status = NT_STATUS_INTERNAL_ERROR;
+ goto fail;
+ }
+ talloc_free(recv_buffer.data);
+ talloc_free(pkt);
+
+ subreq = process_complete_pdu_send(ncacn_conn->ev_ctx,
+ ncacn_conn->p);
+ if (subreq == NULL) {
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq,
+ dcerpc_ncacn_packet_respond,
+ ncacn_conn);
+ return;
}
}
talloc_free(recv_buffer.data);
talloc_free(pkt);
+ /* Wait for the next packet */
+ subreq = dcerpc_read_ncacn_packet_send(ncacn_conn,
+ ncacn_conn->ev_ctx,
+ ncacn_conn->tstream);
+ if (subreq == NULL) {
+ DEBUG(2, ("Failed to start receving packets\n"));
+ status = NT_STATUS_NO_MEMORY;
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, dcerpc_ncacn_packet_process, ncacn_conn);
+ return;
+
+fail:
+ DEBUG(3, ("Terminating client(%s) connection! - '%s'\n",
+ ncacn_conn->client_name, nt_errstr(status)));
+
+ /* Terminate client connection */
+ talloc_free(ncacn_conn);
+ return;
+}
+
+void dcerpc_ncacn_packet_respond(struct tevent_req *subreq)
+{
+ struct dcerpc_ncacn_conn *ncacn_conn =
+ tevent_req_callback_data(subreq, struct dcerpc_ncacn_conn);
+
+ struct _output_data *out;
+ uint32_t to_send;
+ NTSTATUS status;
+
+ process_complete_pdu_recv(subreq);
+ TALLOC_FREE(subreq);
+
+ out = &ncacn_conn->p->out_data;
/*
* This is needed because of the way DCERPC binds work in the RPC
* marshalling code
* a full request, and need to wait for more data from the client
*/
while (out->data_sent_length < out->rdata.length) {
- ok = create_next_pdu(ncacn_conn->p);
+ bool ok = create_next_pdu(ncacn_conn->p);
if (!ok) {
DEBUG(3, ("Failed to create next PDU!\n"));
status = NT_STATUS_UNEXPECTED_IO_ERROR;
typedef void (named_pipe_termination_fn)(void *private_data);
void set_incoming_fault(struct pipes_struct *p);
-void process_complete_pdu(struct pipes_struct *p);
+struct tevent_req *process_complete_pdu_send(struct tevent_context *ev,
+ struct pipes_struct *p);
+void process_complete_pdu_recv(struct tevent_req *req);
int create_named_pipe_socket(const char *pipe_name);
bool setup_named_pipe_socket(const char *pipe_name,
struct tevent_context *ev_ctx,
return True;
}
+struct process_complete_pdu_state {
+ struct pipes_struct *p;
+ bool reply;
+ NTSTATUS status;
+};
/****************************************************************************
Processes a finished PDU stored in p->in_data.pdu.
****************************************************************************/
-void process_complete_pdu(struct pipes_struct *p)
+struct tevent_req *process_complete_pdu_send(struct tevent_context *ev,
+ struct pipes_struct *p)
{
- struct ncacn_packet *pkt = NULL;
+ struct tevent_req *req;
+ struct ncacn_packet *pkt;
NTSTATUS status;
- bool reply = False;
+ struct process_complete_pdu_state *state;
+
+ req = tevent_req_create(p->mem_ctx, &state,
+ struct process_complete_pdu_state);
+ if (req == NULL) {
+ DEBUG(0, ("Out of memory!\n"));
+ return NULL;
+ }
+ state->p = p;
+ state->reply = false;
- if(p->fault_state) {
+ if (p->fault_state) {
DEBUG(10,("RPC connection in fault state.\n"));
- goto done;
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
}
- pkt = talloc(p->mem_ctx, struct ncacn_packet);
- if (!pkt) {
- DEBUG(0, ("Out of memory!\n"));
- goto done;
+ pkt = talloc(state, struct ncacn_packet);
+ if (tevent_req_nomem(pkt, req)) {
+ return tevent_req_post(req, ev);
}
/*
}
DEBUG(10, ("PDU is in %s Endian format!\n", p->endian?"Big":"Little"));
- status = dcerpc_pull_ncacn_packet(pkt, &p->in_data.pdu,
+ status = dcerpc_pull_ncacn_packet(state, &p->in_data.pdu,
pkt, p->endian);
if (!NT_STATUS_IS_OK(status)) {
DEBUG(0, ("Failed to unmarshal rpc packet: %s!\n",
nt_errstr(status)));
- goto done;
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
}
/* Store the call_id */
switch (pkt->ptype) {
case DCERPC_PKT_REQUEST:
- reply = process_request_pdu(p, pkt);
+ state->reply = process_request_pdu(p, pkt);
break;
case DCERPC_PKT_PING: /* CL request - ignore... */
* We assume that a pipe bind is only in one pdu.
*/
if (pipe_init_outgoing_data(p)) {
- reply = api_pipe_bind_req(p, pkt);
+ state->reply = api_pipe_bind_req(p, pkt);
}
break;
* We assume that a pipe bind is only in one pdu.
*/
if (pipe_init_outgoing_data(p)) {
- reply = api_pipe_alter_context(p, pkt);
+ state->reply = api_pipe_alter_context(p, pkt);
}
break;
* The third packet in an auth exchange.
*/
if (pipe_init_outgoing_data(p)) {
- reply = api_pipe_bind_auth3(p, pkt);
+ state->reply = api_pipe_bind_auth3(p, pkt);
}
break;
* If we ever did we'd have to send a cancel_ack reply.
* For now, just free all client data and continue
* processing. */
- reply = True;
+ state->reply = true;
break;
+ /* TODO */
#if 0
/* Enable this if we're doing async rpc. */
/* We must check the outstanding callid matches. */
if (pipe_init_outgoing_data(p)) {
/* Send a cancel_ack PDU reply. */
/* We should probably check the auth-verifier here. */
- reply = setup_cancel_ack_reply(p, pkt);
+ state->reply = setup_cancel_ack_reply(p, pkt);
}
break;
#endif
* processing. */
DEBUG(3, ("process_complete_pdu: DCERPC_PKT_ORPHANED."
" Abandoning rpc call.\n"));
- reply = True;
+ state->reply = true;
break;
default:
break;
}
-done:
- if (!reply) {
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+void process_complete_pdu_recv(struct tevent_req *req)
+{
+ struct process_complete_pdu_state *state
+ = tevent_req_data(req, struct process_complete_pdu_state);
+
+ if (!state->reply) {
DEBUG(3,("DCE/RPC fault sent!"));
- set_incoming_fault(p);
- setup_fault_pdu(p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
- TALLOC_FREE(pkt);
+ set_incoming_fault(state->p);
+ setup_fault_pdu(state->p, NT_STATUS(DCERPC_FAULT_OP_RNG_ERROR));
} else {
/*
* Reset the lengths. We're ready for a new pdu.
*/
- TALLOC_FREE(p->in_data.pdu.data);
- p->in_data.pdu_needed_len = 0;
- p->in_data.pdu.length = 0;
+ TALLOC_FREE(state->p->in_data.pdu.data);
+ state->p->in_data.pdu_needed_len = 0;
+ state->p->in_data.pdu.length = 0;
}
-
- TALLOC_FREE(pkt);
+ tevent_req_received(req);
}
-
return (ssize_t)data_to_copy;
}
+struct write_to_internal_pipe_state {
+ size_t data_processed;
+};
+static void write_to_internal_pipe_done(struct tevent_req *subreq);
+
/****************************************************************************
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)
+static struct tevent_req *write_to_internal_pipe_send(TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct pipes_struct *p,
+ struct iovec *buf)
{
- size_t data_left = n;
+ const char *data = buf->iov_base;
+ size_t data_left = buf->iov_len;
+ struct write_to_internal_pipe_state *state;
+ struct tevent_req *req = tevent_req_create(mem_ctx, &state,
+ struct write_to_internal_pipe_state);
+ if (req == NULL) {
+ return NULL;
+ }
while(data_left) {
ssize_t data_used;
DEBUG(10, ("write_to_pipe: data_used = %d\n",
(int)data_used));
- if(data_used < 0) {
- return -1;
+ if (data_used < 0) {
+ state->data_processed = -1;
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
}
data_left -= data_used;
data += data_used;
if (pdu_ready == true) {
- process_complete_pdu(p);
- break;
+ struct tevent_req *subreq;
+ /* XXX received PDUs are processed one at a time */
+ if (data_left > 0) {
+ DEBUG(0, ("Unacceptable, more than one PDU\n"));
+ state->data_processed = -1;
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+ subreq = process_complete_pdu_send(ev, p);
+ if (subreq == NULL) {
+ state->data_processed = -1;
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+ }
+ state->data_processed = buf->iov_len;
+ tevent_req_set_callback(subreq,
+ write_to_internal_pipe_done,
+ req);
+ return req;
}
}
- return n;
+ state->data_processed = buf->iov_len;
+ tevent_req_done(req);
+ return tevent_req_post(req, ev);
+}
+
+static void write_to_internal_pipe_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req =
+ tevent_req_callback_data(subreq, struct tevent_req);
+
+ process_complete_pdu_recv(subreq);
+ /* data_processed already set, p in fault state on error */
+ tevent_req_done(req);
+}
+
+static size_t write_to_internal_pipe_recv(struct tevent_req *req)
+{
+ struct write_to_internal_pipe_state *state
+ = tevent_req_data(req, struct write_to_internal_pipe_state);
+ size_t ret = state->data_processed;
+
+ tevent_req_received(req);
+ return ret;
}
/****************************************************************************
struct np_write_state {
struct event_context *ev;
- struct np_proxy_state *p;
struct iovec iov;
ssize_t nwritten;
+ enum FAKE_FILE_TYPE type;
+ union {
+ struct pipes_struct *ps;
+ struct np_proxy_state *np;
+ };
};
static void np_write_done(struct tevent_req *subreq);
goto post_status;
}
+ state->ev = ev;
+ state->type = handle->type;
+ state->iov.iov_base = discard_const_p(void, data);
+ state->iov.iov_len = len;
if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE) {
- struct pipes_struct *p = talloc_get_type_abort(
+ struct tevent_req *subreq;
+ state->ps = talloc_get_type_abort(
handle->private_data, struct pipes_struct);
- state->nwritten = write_to_internal_pipe(p, (const char *)data, len);
-
- status = (state->nwritten >= 0)
- ? NT_STATUS_OK : NT_STATUS_UNEXPECTED_IO_ERROR;
- goto post_status;
+ subreq = write_to_internal_pipe_send(state, ev, state->ps,
+ &state->iov);
+ if (subreq == NULL) {
+ goto fail;
+ }
+ tevent_req_set_callback(subreq, np_write_done, req);
+ return req;
}
if (handle->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
- struct np_proxy_state *p = talloc_get_type_abort(
- handle->private_data, struct np_proxy_state);
struct tevent_req *subreq;
-
- state->ev = ev;
- state->p = p;
- state->iov.iov_base = discard_const_p(void, data);
- state->iov.iov_len = len;
+ state->np = talloc_get_type_abort(
+ handle->private_data, struct np_proxy_state);
subreq = tstream_writev_queue_send(state, ev,
- p->npipe,
- p->write_queue,
+ state->np->npipe,
+ state->np->write_queue,
&state->iov, 1);
if (subreq == NULL) {
goto fail;
struct np_write_state *state = tevent_req_data(
req, struct np_write_state);
ssize_t received;
- int err;
- received = tstream_writev_queue_recv(subreq, &err);
- if (received < 0) {
- tevent_req_nterror(req, map_nt_error_from_unix(err));
- return;
+ if (state->type == FAKE_FILE_TYPE_NAMED_PIPE) {
+ received = write_to_internal_pipe_recv(subreq);
+ if (received < 0) {
+ tevent_req_nterror(req, NT_STATUS_UNEXPECTED_IO_ERROR);
+ return;
+ }
+ }
+ if (state->type == FAKE_FILE_TYPE_NAMED_PIPE_PROXY) {
+ int err;
+ received = tstream_writev_queue_recv(subreq, &err);
+ if (received < 0) {
+ tevent_req_nterror(req, map_nt_error_from_unix(err));
+ return;
+ }
}
state->nwritten = received;
tevent_req_done(req);