The branch, v4-0-test has been updated via 9a5f7bf68b20e3b490b209b5cfc4408566320f2e (commit) via 36a39b92d732a682e38ad4b3f733951fee4757ed (commit) via d235ce673705641e06b4ad5f5679e146b59a19e1 (commit) via ba8499867af90dcd88455476b1f58a2ab18f159b (commit) via 66e0c1754f14cf0100ca2d3e9c0cd8c87f9dc1e6 (commit) via 6813e22e9d300696a40993476629227d5cc4d35f (commit) via a6aa055097313975299f214d8ebe8d45aa51d10a (commit) via 1b507a9b8e2ede5a4eb542bdf7a0eab9269b9f7b (commit) via 48ccb51caf7976ec07c8a9bfc1afd3076bf4ee22 (commit) via e1d81388fcabba9a947ed0be9ccae875e2b19135 (commit) via ec67c61b6a82e4f39a15f37a98ae3fe93bb81316 (commit) via 5bf136e233e26b4372155f494bae5118ef777a76 (commit) via 6d84af89ba96627abe142ba7080c24ae2421ed6c (commit) via a65599cc83a12ec61e5a6ba6ad9628619a0dc8a3 (commit) via 4287b7c1323796cf0688d0fae9b5bd4e840e3d48 (commit) via 221f4d6e534a40b7def6e51dc6b4f9e8057d18b7 (commit) from 351947dba3f7a26ac871d4aa7b6bba4cd472383a (commit)
http://gitweb.samba.org/?p=samba.git;a=shortlog;h=v4-0-test - Log ----------------------------------------------------------------- commit 9a5f7bf68b20e3b490b209b5cfc4408566320f2e Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Mon Jul 7 19:40:35 2008 +0200 smb_server/smb: handle incoming multi fragmented nttrans requests metze commit 36a39b92d732a682e38ad4b3f733951fee4757ed Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Mon Jul 7 19:37:14 2008 +0200 smb_server/smb: prepare multi fragmented nttrans requests metze commit d235ce673705641e06b4ad5f5679e146b59a19e1 Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Mon Jul 7 16:34:36 2008 +0200 libcli/raw: remove unused smb_raw_max_trans_data() function metze commit ba8499867af90dcd88455476b1f58a2ab18f159b Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Mon Jul 7 18:07:47 2008 +0200 torture: .in.max_data should not depend on the smb max size We now support async multi fragment SMBtrans calls. metze commit 66e0c1754f14cf0100ca2d3e9c0cd8c87f9dc1e6 Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Mon Jul 7 18:04:44 2008 +0200 rap: trans->in.max_data should not depend on the smb max size We now support async multi fragment SMBtrans calls. metze commit 6813e22e9d300696a40993476629227d5cc4d35f Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Mon Jul 7 18:01:28 2008 +0200 dcerpc_smb: trans->in.max_data should not depend on the smb max size We now support async multi fragment SMBtrans calls. metze commit a6aa055097313975299f214d8ebe8d45aa51d10a Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Mon Jul 7 15:04:59 2008 +0200 libcli/raw: make multi fragmented nttrans requests possible metze commit 1b507a9b8e2ede5a4eb542bdf7a0eab9269b9f7b Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Mon Jul 7 14:00:53 2008 +0200 smb_server/smb: trans(2) setup count is uint8_t metze commit 48ccb51caf7976ec07c8a9bfc1afd3076bf4ee22 Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Mon Jul 7 14:00:09 2008 +0200 libcli/raw: trans(2) setup count is uint8_t metze commit e1d81388fcabba9a947ed0be9ccae875e2b19135 Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Fri Jul 4 20:47:24 2008 +0200 libcli/raw: remove unused smbcli_request_receive_more() function metze commit ec67c61b6a82e4f39a15f37a98ae3fe93bb81316 Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Fri Jul 4 20:46:10 2008 +0200 libcli/raw: use the new recv_helper infrastructure for trans/trans2 replies metze commit 5bf136e233e26b4372155f494bae5118ef777a76 Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Fri Jul 4 20:07:52 2008 +0200 libcli/raw: use the new recv_helper infrastructure for nttrans replies metze commit 6d84af89ba96627abe142ba7080c24ae2421ed6c Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Fri Jul 4 19:52:23 2008 +0200 libcli/raw: add a recv_helper hook infrastructure The recv helper will be called when a response comes and the recv helper can decide to let the request on the SMBCLI_REQUEST_RECV when more reponse packets are expected. It's up to the helper function to keep a reference to the in buffers, each incoming response overwrites req->in. metze commit a65599cc83a12ec61e5a6ba6ad9628619a0dc8a3 Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Fri Jul 4 20:16:36 2008 +0200 libcli/raw: the nttrans setup count is only 8-bit metze commit 4287b7c1323796cf0688d0fae9b5bd4e840e3d48 Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Mon Jul 7 13:00:24 2008 +0200 smb_server/smb: transs and transs2 calls have different word counts Also add a note about NT_STATUS_DOS(ERRSRV, ERRerror). metze commit 221f4d6e534a40b7def6e51dc6b4f9e8057d18b7 Author: Stefan Metzmacher <[EMAIL PROTECTED]> Date: Mon Jul 7 12:56:26 2008 +0200 smb_server/smb: fix crash bug with fragmented trans calls We need to use smbsrv_setup_secondary_request(req) to send the trans ack, because smbsrv_send_reply(req) destroys 'req' and the partial trans list had dead elements in the list. Also make sure the partial list element is removed by a talloc destructor. metze ----------------------------------------------------------------------- Summary of changes: source/libcli/raw/clitransport.c | 16 +- source/libcli/raw/interfaces.h | 2 +- source/libcli/raw/libcliraw.h | 8 + source/libcli/raw/rawrequest.c | 13 - source/libcli/raw/rawtrans.c | 967 +++++++++++++++++++++++++------------- source/librpc/rpc/dcerpc_smb.c | 9 +- source/smb_server/smb/nttrans.c | 168 ++++++- source/smb_server/smb/trans2.c | 55 ++- source/smb_server/smb_server.h | 5 +- source/torture/basic/aliases.c | 10 +- source/torture/basic/scanner.c | 8 +- source/torture/rap/rap.c | 2 +- 12 files changed, 880 insertions(+), 383 deletions(-) Changeset truncated at 500 lines: diff --git a/source/libcli/raw/clitransport.c b/source/libcli/raw/clitransport.c index 34fb962..e95ae32 100644 --- a/source/libcli/raw/clitransport.c +++ b/source/libcli/raw/clitransport.c @@ -480,8 +480,22 @@ async: /* if this request has an async handler then call that to notify that the reply has been received. This might destroy the request so it must happen last */ - DLIST_REMOVE(transport->pending_recv, req); + req->state = SMBCLI_REQUEST_DONE; + + if (req->recv_helper.fn) { + /* + * let the recv helper decide in + * what state the request really is + */ + req->state = req->recv_helper.fn(req); + + /* if more parts are needed, wait for them */ + if (req->state <= SMBCLI_REQUEST_RECV) { + return NT_STATUS_OK; + } + } + DLIST_REMOVE(transport->pending_recv, req); if (req->async.fn) { req->async.fn(req); } diff --git a/source/libcli/raw/interfaces.h b/source/libcli/raw/interfaces.h index 8e23510..537041c 100644 --- a/source/libcli/raw/interfaces.h +++ b/source/libcli/raw/interfaces.h @@ -2258,7 +2258,7 @@ struct smb_nttrans { uint8_t max_setup; uint32_t max_param; uint32_t max_data; - uint32_t setup_count; + uint8_t setup_count; uint16_t function; uint8_t *setup; DATA_BLOB params; diff --git a/source/libcli/raw/libcliraw.h b/source/libcli/raw/libcliraw.h index 16a98ad..d55b4cc 100644 --- a/source/libcli/raw/libcliraw.h +++ b/source/libcli/raw/libcliraw.h @@ -231,6 +231,14 @@ struct smbcli_request { struct smbcli_session *session; struct smbcli_tree *tree; + /* a receive helper, smbcli_transport_finish_recv will not call + req->async.fn callback handler unless the recv_helper returns + a value > SMBCLI_REQUEST_RECV. */ + struct { + enum smbcli_request_state (*fn)(struct smbcli_request *); + void *private_data; + } recv_helper; + /* the flags2 from the SMB request, in raw form (host byte order). Used to parse strings */ uint16_t flags2; diff --git a/source/libcli/raw/rawrequest.c b/source/libcli/raw/rawrequest.c index ef856c6..a0e6452 100644 --- a/source/libcli/raw/rawrequest.c +++ b/source/libcli/raw/rawrequest.c @@ -365,19 +365,6 @@ bool smbcli_request_receive(struct smbcli_request *req) /* - receive another reply to a request - this is used for requests that - have multi-part replies (such as SMBtrans2) -*/ -bool smbcli_request_receive_more(struct smbcli_request *req) -{ - req->state = SMBCLI_REQUEST_RECV; - DLIST_ADD(req->transport->pending_recv, req); - - return smbcli_request_receive(req); -} - - -/* handle oplock break requests from the server - return true if the request was an oplock break */ diff --git a/source/libcli/raw/rawtrans.c b/source/libcli/raw/rawtrans.c index 0f15b21..2f52986 100644 --- a/source/libcli/raw/rawtrans.c +++ b/source/libcli/raw/rawtrans.c @@ -49,148 +49,188 @@ static bool raw_trans_oob(struct smbcli_request *req, return false; } -/**************************************************************************** - receive a SMB trans or trans2 response allocating the necessary memory - ****************************************************************************/ +static size_t raw_trans_space_left(struct smbcli_request *req) +{ + if (req->transport->negotiate.max_xmit <= req->out.size) { + return 0; + } + + return req->transport->negotiate.max_xmit - req->out.size; +} + +struct smb_raw_trans2_recv_state { + uint8_t command; + uint32_t params_total; + uint32_t data_total; + uint32_t params_left; + uint32_t data_left; + bool got_first; + uint32_t recvd_data; + uint32_t recvd_param; + struct smb_trans2 io; +}; + NTSTATUS smb_raw_trans2_recv(struct smbcli_request *req, TALLOC_CTX *mem_ctx, struct smb_trans2 *parms) { - int total_data=0; - int total_param=0; - uint8_t *tdata; - uint8_t *tparam; - - parms->out.data.length = 0; - parms->out.data.data = NULL; - parms->out.params.length = 0; - parms->out.params.data = NULL; + struct smb_raw_trans2_recv_state *state; - if (!smbcli_request_receive(req)) { - return smbcli_request_destroy(req); + if (!smbcli_request_receive(req) || + smbcli_request_is_error(req)) { + goto failed; } - + + state = talloc_get_type(req->recv_helper.private_data, + struct smb_raw_trans2_recv_state); + + parms->out = state->io.out; + talloc_steal(mem_ctx, parms->out.setup); + talloc_steal(mem_ctx, parms->out.params.data); + talloc_steal(mem_ctx, parms->out.data.data); + talloc_free(state); + + ZERO_STRUCT(req->recv_helper); + +failed: + return smbcli_request_destroy(req); +} + +static enum smbcli_request_state smb_raw_trans2_ship_rest(struct smbcli_request *req, + struct smb_raw_trans2_recv_state *state); + +/* + * This helper returns SMBCLI_REQUEST_RECV until all data has arrived + */ +static enum smbcli_request_state smb_raw_trans2_recv_helper(struct smbcli_request *req) +{ + struct smb_raw_trans2_recv_state *state = talloc_get_type(req->recv_helper.private_data, + struct smb_raw_trans2_recv_state); + uint16_t param_count, param_ofs, param_disp; + uint16_t data_count, data_ofs, data_disp; + uint16_t total_data, total_param; + uint8_t setup_count; + /* * An NT RPC pipe call can return ERRDOS, ERRmoredata * to a trans call. This is not an error and should not * be treated as such. */ - if (NT_STATUS_IS_ERR(req->status)) { - return smbcli_request_destroy(req); + if (smbcli_request_is_error(req)) { + goto failed; + } + + if (state->params_left > 0 || state->data_left > 0) { + return smb_raw_trans2_ship_rest(req, state); } SMBCLI_CHECK_MIN_WCT(req, 10); - /* parse out the lengths */ total_data = SVAL(req->in.vwv, VWV(1)); total_param = SVAL(req->in.vwv, VWV(0)); - - /* allocate it */ - if (total_data != 0) { - tdata = talloc_array(mem_ctx, uint8_t, total_data); - if (!tdata) { - DEBUG(0,("smb_raw_receive_trans: failed to enlarge data buffer to %d bytes\n", total_data)); - req->status = NT_STATUS_NO_MEMORY; - return smbcli_request_destroy(req); + setup_count = CVAL(req->in.vwv, VWV(9)); + + param_count = SVAL(req->in.vwv, VWV(3)); + param_ofs = SVAL(req->in.vwv, VWV(4)); + param_disp = SVAL(req->in.vwv, VWV(5)); + + data_count = SVAL(req->in.vwv, VWV(6)); + data_ofs = SVAL(req->in.vwv, VWV(7)); + data_disp = SVAL(req->in.vwv, VWV(8)); + + if (!state->got_first) { + if (total_param > 0) { + state->io.out.params = data_blob_talloc(state, NULL, total_param); + if (!state->io.out.params.data) { + goto nomem; + } } - parms->out.data.data = tdata; - } - if (total_param != 0) { - tparam = talloc_array(mem_ctx, uint8_t, total_param); - if (!tparam) { - DEBUG(0,("smb_raw_receive_trans: failed to enlarge param buffer to %d bytes\n", total_param)); - req->status = NT_STATUS_NO_MEMORY; - return smbcli_request_destroy(req); + if (total_data > 0) { + state->io.out.data = data_blob_talloc(state, NULL, total_data); + if (!state->io.out.data.data) { + goto nomem; + } } - parms->out.params.data = tparam; - } - parms->out.setup_count = SVAL(req->in.vwv, VWV(9)); - SMBCLI_CHECK_WCT(req, 10 + parms->out.setup_count); + if (setup_count > 0) { + uint16_t i; - if (parms->out.setup_count > 0) { - int i; - parms->out.setup = talloc_array(mem_ctx, uint16_t, parms->out.setup_count); - if (!parms->out.setup) { - req->status = NT_STATUS_NO_MEMORY; - return smbcli_request_destroy(req); - } - for (i=0;i<parms->out.setup_count;i++) { - parms->out.setup[i] = SVAL(req->in.vwv, VWV(10+i)); + SMBCLI_CHECK_WCT(req, 10 + setup_count); + + state->io.out.setup_count = setup_count; + state->io.out.setup = talloc_array(state, uint16_t, setup_count); + if (!state->io.out.setup) { + goto nomem; + } + for (i=0; i < setup_count; i++) { + state->io.out.setup[i] = SVAL(req->in.vwv, VWV(10+i)); + } } - } - while (1) { - uint16_t param_count, param_ofs, param_disp; - uint16_t data_count, data_ofs, data_disp; - uint16_t total_data2, total_param2; + state->got_first = true; + } - /* parse out the total lengths again - they can shrink! */ - total_data2 = SVAL(req->in.vwv, VWV(1)); - total_param2 = SVAL(req->in.vwv, VWV(0)); + if (total_data > state->io.out.data.length || + total_param > state->io.out.params.length) { + /* they must *only* shrink */ + DEBUG(1,("smb_raw_trans2_recv_helper: data/params expanded!\n")); + req->status = NT_STATUS_BUFFER_TOO_SMALL; + goto failed; + } - if (total_data2 > total_data || - total_param2 > total_param) { - /* they must *only* shrink */ - DEBUG(1,("smb_raw_receive_trans: data/params expanded!\n")); - req->status = NT_STATUS_BUFFER_TOO_SMALL; - return smbcli_request_destroy(req); - } + state->io.out.data.length = total_data; + state->io.out.params.length = total_param; - total_data = total_data2; - total_param = total_param2; + if (data_count + data_disp > total_data || + param_count + param_disp > total_param) { + DEBUG(1,("smb_raw_trans2_recv_helper: Buffer overflow\n")); + req->status = NT_STATUS_BUFFER_TOO_SMALL; + goto failed; + } - /* parse params for this lump */ - param_count = SVAL(req->in.vwv, VWV(3)); - param_ofs = SVAL(req->in.vwv, VWV(4)); - param_disp = SVAL(req->in.vwv, VWV(5)); + /* check the server isn't being nasty */ + if (raw_trans_oob(req, param_ofs, param_count) || + raw_trans_oob(req, data_ofs, data_count)) { + DEBUG(1,("smb_raw_trans2_recv_helper: out of bounds parameters!\n")); + req->status = NT_STATUS_BUFFER_TOO_SMALL; + goto failed; + } - data_count = SVAL(req->in.vwv, VWV(6)); - data_ofs = SVAL(req->in.vwv, VWV(7)); - data_disp = SVAL(req->in.vwv, VWV(8)); + if (data_count) { + memcpy(state->io.out.data.data + data_disp, + req->in.hdr + data_ofs, + data_count); + } - if (data_count + data_disp > total_data || - param_count + param_disp > total_param) { - DEBUG(1,("smb_raw_receive_trans: Buffer overflow\n")); - req->status = NT_STATUS_BUFFER_TOO_SMALL; - return smbcli_request_destroy(req); - } - - /* check the server isn't being nasty */ - if (raw_trans_oob(req, param_ofs, param_count) || - raw_trans_oob(req, data_ofs, data_count)) { - DEBUG(1,("smb_raw_receive_trans: out of bounds parameters!\n")); - req->status = NT_STATUS_BUFFER_TOO_SMALL; - return smbcli_request_destroy(req); - } + if (param_count) { + memcpy(state->io.out.params.data + param_disp, + req->in.hdr + param_ofs, + param_count); + } - if (data_count) { - memcpy(parms->out.data.data + data_disp, - req->in.hdr + data_ofs, - data_count); - } + state->recvd_param += param_count; + state->recvd_data += data_count; - if (param_count) { - memcpy(parms->out.params.data + param_disp, - req->in.hdr + param_ofs, - param_count); - } + if (state->recvd_data < total_data || + state->recvd_param < total_param) { - parms->out.data.length += data_count; - parms->out.params.length += param_count; + /* we don't need the in buffer any more */ + talloc_free(req->in.buffer); + ZERO_STRUCT(req->in); - if (total_data <= parms->out.data.length && total_param <= parms->out.params.length) - break; - - if (!smbcli_request_receive_more(req)) { - req->status = NT_STATUS_UNSUCCESSFUL; - return smbcli_request_destroy(req); - } + /* we still wait for more data */ + DEBUG(10,("smb_raw_trans2_recv_helper: more data needed\n")); + return SMBCLI_REQUEST_RECV; } + DEBUG(10,("smb_raw_trans2_recv_helper: done\n")); + return SMBCLI_REQUEST_DONE; + +nomem: + req->status = NT_STATUS_NO_MEMORY; failed: - return smbcli_request_destroy(req); + return SMBCLI_REQUEST_ERROR; } _PUBLIC_ NTSTATUS smb_raw_trans_recv(struct smbcli_request *req, @@ -208,13 +248,17 @@ struct smbcli_request *smb_raw_trans_send_backend(struct smbcli_tree *tree, struct smb_trans2 *parms, uint8_t command) { - int wct = 14 + parms->in.setup_count; - struct smbcli_request *req, *req2; - uint8_t *outdata,*outparam; + struct smb_raw_trans2_recv_state *state; + struct smbcli_request *req; int i; int padding; + size_t space_left; size_t namelen = 0; - uint16_t data_disp, data_length, max_data; + DATA_BLOB params_chunk; + uint16_t ofs; + uint16_t params_ofs = 0; + DATA_BLOB data_chunk; + uint16_t data_ofs = 0; if (parms->in.params.length > UINT16_MAX || parms->in.data.length > UINT16_MAX) { @@ -229,136 +273,223 @@ struct smbcli_request *smb_raw_trans_send_backend(struct smbcli_tree *tree, else padding = 3; - req = smbcli_request_setup(tree, command, wct, padding); + req = smbcli_request_setup(tree, command, + 14 + parms->in.setup_count, + padding); if (!req) { return NULL; } + state = talloc_zero(req, struct smb_raw_trans2_recv_state); + if (!state) { + smbcli_request_destroy(req); + return NULL; + } + + state->command = command; + + /* make sure we don't leak data via the padding */ + memset(req->out.data, 0, padding); + /* Watch out, this changes the req->out.* pointers */ if (command == SMBtrans && parms->in.trans_name) { namelen = smbcli_req_append_string(req, parms->in.trans_name, STR_TERMINATE); } - /* fill in SMB parameters */ - outparam = req->out.data + padding; - outdata = outparam + parms->in.params.length; + ofs = PTR_DIFF(req->out.data,req->out.hdr)+padding+namelen; - /* make sure we don't leak data via the padding */ - memset(req->out.data, 0, padding); + /* see how much bytes of the params block we can ship in the first request */ + space_left = raw_trans_space_left(req); - data_length = parms->in.data.length; + params_chunk.length = MIN(parms->in.params.length, space_left); + params_chunk.data = parms->in.params.data; + params_ofs = ofs; - max_data = smb_raw_max_trans_data(tree, parms->in.params.length); - if (max_data < data_length) { - data_length = max_data; + state->params_left = parms->in.params.length - params_chunk.length; + + if (state->params_left > 0) { + /* we copy the whole params block, if needed we can optimize that latter */ + state->io.in.params = data_blob_talloc(state, NULL, parms->in.params.length); + if (!state->io.in.params.data) { + smbcli_request_destroy(req); + return NULL; + } + memcpy(state->io.in.params.data, + parms->in.params.data, + parms->in.params.length); } + /* see how much bytes of the data block we can ship in the first request */ + space_left -= params_chunk.length; + #if TORTURE_TRANS_DATA - if (data_length > 1) { - data_length /= 2; + if (space_left > 1) { + space_left /= 2; } #endif + data_chunk.length = MIN(parms->in.data.length, space_left); + data_chunk.data = parms->in.data.data; + data_ofs = params_ofs + params_chunk.length; + + state->data_left = parms->in.data.length - data_chunk.length; + + if (state->data_left > 0) { + /* we copy the whole params block, if needed we can optimize that latter */ + state->io.in.data = data_blob_talloc(state, NULL, parms->in.data.length); + if (!state->io.in.data.data) { + smbcli_request_destroy(req); + return NULL; + } + memcpy(state->io.in.data.data, + parms->in.data.data, + parms->in.data.length); + } + + state->params_total = parms->in.params.length; + state->data_total = parms->in.data.length; + /* primary request */ SSVAL(req->out.vwv,VWV(0),parms->in.params.length); SSVAL(req->out.vwv,VWV(1),parms->in.data.length); -- Samba Shared Repository