summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/include/smb.h16
-rw-r--r--source3/smbd/ipc.c148
2 files changed, 135 insertions, 29 deletions
diff --git a/source3/include/smb.h b/source3/include/smb.h
index be6ccbf597..491dd763ff 100644
--- a/source3/include/smb.h
+++ b/source3/include/smb.h
@@ -624,7 +624,18 @@ struct smb_request {
uint16_t buflen;
const uint8_t *buf;
const uint8 *inbuf;
+
+ /*
+ * Async handling in the main smb processing loop is directed by
+ * outbuf: reply_xxx routines indicate sync behaviour by putting their
+ * reply into "outbuf". If they leave it as NULL, they take of it
+ * themselves, possibly later.
+ *
+ * If async handling is wanted, the reply_xxx routine must make sure
+ * that it talloc_move()s the smb_req somewhere else.
+ */
uint8 *outbuf;
+
size_t unread_bytes;
bool encrypted;
connection_struct *conn;
@@ -638,6 +649,11 @@ struct smb_request {
* Here we collect the outbufs from the chain handlers
*/
uint8_t *chain_outbuf;
+
+ /*
+ * state information for async smb handling
+ */
+ void *async_priv;
};
/* Defines for the sent_oplock_break field above. */
diff --git a/source3/smbd/ipc.c b/source3/smbd/ipc.c
index 7c150561b1..9c7528dfa7 100644
--- a/source3/smbd/ipc.c
+++ b/source3/smbd/ipc.c
@@ -204,40 +204,137 @@ void send_trans_reply(connection_struct *conn,
Start the first part of an RPC reply which began with an SMBtrans request.
****************************************************************************/
-static void api_rpc_trans_reply(connection_struct *conn,
- struct smb_request *req,
- files_struct *fsp,
- int max_trans_reply)
+struct dcerpc_cmd_state {
+ struct fake_file_handle *handle;
+ uint8_t *data;
+ size_t num_data;
+ size_t max_read;
+};
+
+static void api_dcerpc_cmd_write_done(struct async_req *subreq);
+static void api_dcerpc_cmd_read_done(struct async_req *subreq);
+
+static void api_dcerpc_cmd(connection_struct *conn, struct smb_request *req,
+ files_struct *fsp, uint8_t *data, size_t length,
+ size_t max_read)
{
- bool is_data_outstanding;
- uint8_t *rdata = SMB_MALLOC_ARRAY(uint8_t, max_trans_reply);
- ssize_t data_len;
- NTSTATUS status;
+ struct async_req *subreq;
+ struct dcerpc_cmd_state *state;
+
+ if (!fsp_is_np(fsp)) {
+ api_no_reply(conn, req);
+ return;
+ }
- if(rdata == NULL) {
- DEBUG(0,("api_rpc_trans_reply: malloc fail.\n"));
+ state = talloc(req, struct dcerpc_cmd_state);
+ if (state == NULL) {
reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
+ req->async_priv = state;
- if (!fsp_is_np(fsp)) {
- SAFE_FREE(rdata);
- api_no_reply(conn,req);
+ state->handle = fsp->fake_file_handle;
+
+ /*
+ * This memdup severely sucks. But doing it properly essentially means
+ * to rewrite lanman.c, something which I don't really want to do now.
+ */
+ state->data = (uint8_t *)talloc_memdup(state, data, length);
+ if (state->data == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
return;
}
+ state->num_data = length;
+ state->max_read = max_read;
+
+ subreq = np_write_send(state, smbd_event_context(), state->handle,
+ state->data, length);
+ if (subreq == NULL) {
+ TALLOC_FREE(state);
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ return;
+ }
+ subreq->async.fn = api_dcerpc_cmd_write_done;
+ subreq->async.priv = talloc_move(conn, &req);
+}
+
+static void api_dcerpc_cmd_write_done(struct async_req *subreq)
+{
+ struct smb_request *req = talloc_get_type_abort(
+ subreq->async.priv, struct smb_request);
+ struct dcerpc_cmd_state *state = talloc_get_type_abort(
+ req->async_priv, struct dcerpc_cmd_state);
+ NTSTATUS status;
+ ssize_t nwritten = -1;
+
+ status = np_write_recv(subreq, &nwritten);
+ TALLOC_FREE(subreq);
+ if (!NT_STATUS_IS_OK(status) || (nwritten != state->num_data)) {
+ DEBUG(10, ("Could not write to pipe: %s (%d/%d)\n",
+ nt_errstr(status), (int)state->num_data,
+ (int)nwritten));
+ reply_nterror(req, NT_STATUS_PIPE_NOT_AVAILABLE);
+ goto send;
+ }
+
+ state->data = TALLOC_REALLOC_ARRAY(state, state->data, uint8_t,
+ state->max_read);
+ if (state->data == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ goto send;
+ }
+
+ subreq = np_read_send(req->conn, smbd_event_context(),
+ state->handle, state->data, state->max_read);
+ if (subreq == NULL) {
+ reply_nterror(req, NT_STATUS_NO_MEMORY);
+ goto send;
+ }
+
+ subreq->async.fn = api_dcerpc_cmd_read_done;
+ subreq->async.priv = req;
+ return;
+
+ send:
+ if (!srv_send_smb(
+ smbd_server_fd(), (char *)req->outbuf,
+ IS_CONN_ENCRYPTED(req->conn) || req->encrypted)) {
+ exit_server_cleanly("construct_reply: srv_send_smb failed.");
+ }
+ TALLOC_FREE(req);
+}
+
+static void api_dcerpc_cmd_read_done(struct async_req *subreq)
+{
+ struct smb_request *req = talloc_get_type_abort(
+ subreq->async.priv, struct smb_request);
+ struct dcerpc_cmd_state *state = talloc_get_type_abort(
+ req->async_priv, struct dcerpc_cmd_state);
+ NTSTATUS status;
+ ssize_t nread;
+ bool is_data_outstanding;
+
+ status = np_read_recv(subreq, &nread, &is_data_outstanding);
+ TALLOC_FREE(subreq);
- status = np_read(fsp->fake_file_handle, rdata, max_trans_reply,
- &data_len, &is_data_outstanding);
if (!NT_STATUS_IS_OK(status)) {
- SAFE_FREE(rdata);
- api_no_reply(conn,req);
+ DEBUG(10, ("Could not read from to pipe: %s\n",
+ nt_errstr(status)));
+ reply_nterror(req, status);
+
+ if (!srv_send_smb(smbd_server_fd(), (char *)req->outbuf,
+ IS_CONN_ENCRYPTED(req->conn)
+ ||req->encrypted)) {
+ exit_server_cleanly("construct_reply: srv_send_smb "
+ "failed.");
+ }
+ TALLOC_FREE(req);
return;
}
- send_trans_reply(conn, req, NULL, 0, (char *)rdata, data_len,
+ send_trans_reply(req->conn, req, NULL, 0, (char *)state->data, nread,
is_data_outstanding);
- SAFE_FREE(rdata);
- return;
+ TALLOC_FREE(req);
}
/****************************************************************************
@@ -310,7 +407,6 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid,
struct files_struct *fsp;
int pnum;
int subcommand;
- NTSTATUS status;
DEBUG(5,("api_fd_reply\n"));
@@ -360,14 +456,8 @@ static void api_fd_reply(connection_struct *conn, uint16 vuid,
switch (subcommand) {
case TRANSACT_DCERPCCMD: {
/* dce/rpc command */
- ssize_t nwritten;
- status = np_write(fsp->fake_file_handle, data, tdscnt,
- &nwritten);
- if (!NT_STATUS_IS_OK(status)) {
- api_no_reply(conn, req);
- return;
- }
- api_rpc_trans_reply(conn, req, fsp, mdrcnt);
+ api_dcerpc_cmd(conn, req, fsp, (uint8_t *)data, tdscnt,
+ mdrcnt);
break;
}
case TRANSACT_WAITNAMEDPIPEHANDLESTATE: