From e05250c02644b4c8ff6f1bdaa7342a10f094f269 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 00:40:54 +0200 Subject: [PATCH 01/14] s3:libsmb/async_smb: let cli_smb_recv() initialize output values for one way requests metze (cherry picked from commit 49cdf171a5198495aead9ace43963e805331e20b) --- source3/libsmb/async_smb.c | 18 ++++++++++++++++++ 1 files changed, 18 insertions(+), 0 deletions(-) diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c index 8c5627d..1f72f1a 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -783,6 +783,24 @@ NTSTATUS cli_smb_recv(struct tevent_req *req, } if (state->inbuf == NULL) { + if (min_wct != 0) { + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + if (pinbuf) { + *pinbuf = NULL; + } + if (pwct) { + *pwct = 0; + } + if (pvwv) { + *pvwv = NULL; + } + if (pnum_bytes) { + *pnum_bytes = 0; + } + if (pbytes) { + *pbytes = NULL; + } /* This was a request without a reply */ return NT_STATUS_OK; } -- 1.7.4.1 From bbf548f71b3297b3788a8d48b0df9ddfd2c62d3c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 14:14:24 +0200 Subject: [PATCH 02/14] s3:libsmb/async_smb: call cli_smb_req_unset_pending() instead of destructor directly metze (cherry picked from commit 173fc258e443d97e4ea37f2bee99c21ad15ab484) --- source3/libsmb/async_smb.c | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c index 1f72f1a..aa9e4ad 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -716,7 +716,7 @@ static void cli_smb_received(struct tevent_req *subreq) if (state->chained_requests == NULL) { state->inbuf = talloc_move(state, &inbuf); talloc_set_destructor(req, NULL); - cli_smb_req_destructor(req); + cli_smb_req_unset_pending(req); state->chain_num = 0; state->chain_length = 1; tevent_req_done(req); @@ -760,7 +760,7 @@ static void cli_smb_received(struct tevent_req *subreq) while (talloc_array_length(cli->pending) > 0) { req = cli->pending[0]; talloc_set_destructor(req, NULL); - cli_smb_req_destructor(req); + cli_smb_req_unset_pending(req); tevent_req_nterror(req, status); } } -- 1.7.4.1 From 279322d6af1689d290799824163b6885006f769f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 10:20:25 +0200 Subject: [PATCH 03/14] s3:libsmb/async_smb: don't remove pending requests if the mid is set If the mid was set explicitly, it means the request expects more than one reply, so leave it in the pending array. metze (cherry picked from commit a25936f1b1300a76b08a6bd435bd7ccc388279d5) --- source3/libsmb/async_smb.c | 15 +++++++++++++++ 1 files changed, 15 insertions(+), 0 deletions(-) diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c index aa9e4ad..e352e3d 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -239,6 +239,14 @@ void cli_smb_req_unset_pending(struct tevent_req *req) int num_pending = talloc_array_length(cli->pending); int i; + if (state->mid != 0) { + /* + * This is a [nt]trans[2] request which waits + * for more than one reply. + */ + return; + } + if (num_pending == 1) { /* * The pending read_smb tevent_req is a child of @@ -281,6 +289,13 @@ void cli_smb_req_unset_pending(struct tevent_req *req) static int cli_smb_req_destructor(struct tevent_req *req) { + struct cli_smb_state *state = tevent_req_data( + req, struct cli_smb_state); + /* + * Make sure we really remove it from + * the pending array on destruction. + */ + state->mid = 0; cli_smb_req_unset_pending(req); return 0; } -- 1.7.4.1 From 7f097c07fb02c8aead97c4a77976c9f3cc6955ef Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 9 Jun 2011 11:49:48 +0200 Subject: [PATCH 04/14] s3:libsmb/async_smb: add helpers to get and set the seqnum for signing This will be used for correct signing in [nt]trans[2][s] requests. metze (cherry picked from commit 3dd1ebd21ee99d130f6dd30326ddafe3f00a50d0) --- source3/include/async_smb.h | 2 ++ source3/libsmb/async_smb.c | 14 ++++++++++++++ 2 files changed, 16 insertions(+), 0 deletions(-) diff --git a/source3/include/async_smb.h b/source3/include/async_smb.h index a8852b2..1685d49 100644 --- a/source3/include/async_smb.h +++ b/source3/include/async_smb.h @@ -51,6 +51,8 @@ void cli_smb_req_unset_pending(struct tevent_req *req); bool cli_smb_req_set_pending(struct tevent_req *req); uint16_t cli_smb_req_mid(struct tevent_req *req); void cli_smb_req_set_mid(struct tevent_req *req, uint16_t mid); +uint32_t cli_smb_req_seqnum(struct tevent_req *req); +void cli_smb_req_set_seqnum(struct tevent_req *req, uint32_t seqnum); struct tevent_req *cli_smb_send(TALLOC_CTX *mem_ctx, struct event_context *ev, struct cli_state *cli, uint8_t smb_command, uint8_t additional_flags, diff --git a/source3/libsmb/async_smb.c b/source3/libsmb/async_smb.c index e352e3d..7b4cf01 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -358,6 +358,20 @@ void cli_smb_req_set_mid(struct tevent_req *req, uint16_t mid) state->mid = mid; } +uint32_t cli_smb_req_seqnum(struct tevent_req *req) +{ + struct cli_smb_state *state = tevent_req_data( + req, struct cli_smb_state); + return state->seqnum; +} + +void cli_smb_req_set_seqnum(struct tevent_req *req, uint32_t seqnum) +{ + struct cli_smb_state *state = tevent_req_data( + req, struct cli_smb_state); + state->seqnum = seqnum; +} + static size_t iov_len(const struct iovec *iov, int count) { size_t result = 0; -- 1.7.4.1 From dfa801dc5d0910c53330cadc12a91de947fb93a4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 00:37:24 +0200 Subject: [PATCH 05/14] s3:libsmb/clitrans: remove unused secondary_request_ctx metze (cherry picked from commit 2ae565b681a6307886b888ee5b576c12916eb0db) --- source3/libsmb/clitrans.c | 2 -- 1 files changed, 0 insertions(+), 2 deletions(-) diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c index 090ed11..e4e312f 100644 --- a/source3/libsmb/clitrans.c +++ b/source3/libsmb/clitrans.c @@ -52,8 +52,6 @@ struct cli_trans_state { struct trans_recvblob rdata; uint16_t recv_flags2; - TALLOC_CTX *secondary_request_ctx; - struct iovec iov[4]; uint8_t pad[4]; uint16_t vwv[32]; -- 1.7.4.1 From 1c9d698b805119ca8dd6951ca1fa6e0b4b914da5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 17:08:00 +0200 Subject: [PATCH 06/14] s3:libsmb/clitrans: use uint32_t for param and data variables SMBnttrans uses 32-bit values there. metze (cherry picked from commit 428a86c92b5b35e28c7d6921f2999616cdc1bc20) --- source3/libsmb/clitrans.c | 6 +++--- 1 files changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c index e4e312f..c0f5408 100644 --- a/source3/libsmb/clitrans.c +++ b/source3/libsmb/clitrans.c @@ -171,9 +171,9 @@ static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct, struct iovec *iov = state->iov; uint8_t *pad = state->pad; uint16_t *vwv = state->vwv; - uint16_t param_offset; - uint16_t this_param = 0; - uint16_t this_data = 0; + uint32_t param_offset; + uint32_t this_param = 0; + uint32_t this_data = 0; uint32_t useable_space; uint8_t cmd; -- 1.7.4.1 From 53b8f337d5e63e1285139d419cbef6ae71cd36c3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 9 Jun 2011 12:22:59 +0200 Subject: [PATCH 07/14] s3:libsmb/clitrans: marshall SMBnttrans[2] as the others This is just to make the code more readable and easier to notice how many words we're using in vwv. metze (cherry picked from commit 6f7af1b0388d30c8a06c495713066b90ded00780) --- source3/libsmb/clitrans.c | 46 ++++++++++++++++++++++---------------------- 1 files changed, 23 insertions(+), 23 deletions(-) diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c index c0f5408..025ea93 100644 --- a/source3/libsmb/clitrans.c +++ b/source3/libsmb/clitrans.c @@ -289,33 +289,33 @@ static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct, } break; case SMBnttrans: - SCVAL(vwv, 0, state->max_setup); - SSVAL(vwv, 1, 0); /* reserved */ - SIVAL(vwv, 3, state->num_param); - SIVAL(vwv, 7, state->num_data); - SIVAL(vwv, 11, state->rparam.max); - SIVAL(vwv, 15, state->rdata.max); - SIVAL(vwv, 19, this_param); - SIVAL(vwv, 23, param_offset); - SIVAL(vwv, 27, this_data); - SIVAL(vwv, 31, param_offset + this_param); - SCVAL(vwv, 35, state->num_setup); - SSVAL(vwv, 36, state->function); + SCVAL(vwv + 0, 0, state->max_setup); + SSVAL(vwv + 0, 1, 0); /* reserved */ + SIVAL(vwv + 1, 1, state->num_param); + SIVAL(vwv + 3, 1, state->num_data); + SIVAL(vwv + 5, 1, state->rparam.max); + SIVAL(vwv + 7, 1, state->rdata.max); + SIVAL(vwv + 9, 1, this_param); + SIVAL(vwv +11, 1, param_offset); + SIVAL(vwv +13, 1, this_data); + SIVAL(vwv +15, 1, param_offset + this_param); + SCVAL(vwv +17, 1, state->num_setup); + SSVAL(vwv +18, 0, state->function); memcpy(vwv + 19, state->setup, sizeof(uint16_t) * state->num_setup); break; case SMBnttranss: - SSVAL(vwv, 0, 0); /* reserved */ - SCVAL(vwv, 2, 0); /* reserved */ - SIVAL(vwv, 3, state->num_param); - SIVAL(vwv, 7, state->num_data); - SIVAL(vwv, 11, this_param); - SIVAL(vwv, 15, param_offset); - SIVAL(vwv, 19, state->param_sent); - SIVAL(vwv, 23, this_data); - SIVAL(vwv, 27, param_offset + this_param); - SIVAL(vwv, 31, state->data_sent); - SCVAL(vwv, 35, 0); /* reserved */ + SSVAL(vwv + 0, 0, 0); /* reserved */ + SCVAL(vwv + 1, 0, 0); /* reserved */ + SIVAL(vwv + 1, 1, state->num_param); + SIVAL(vwv + 3, 1, state->num_data); + SIVAL(vwv + 5, 1, this_param); + SIVAL(vwv + 7, 1, param_offset); + SIVAL(vwv + 9, 1, state->param_sent); + SIVAL(vwv +11, 1, this_data); + SIVAL(vwv +13, 1, param_offset + this_param); + SIVAL(vwv +15, 1, state->data_sent); + SCVAL(vwv +17, 1, 0); /* reserved */ break; } -- 1.7.4.1 From 5fa84a0ff5e3dfe8be6ac31ba2740fad4b5d0acc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 00:44:34 +0200 Subject: [PATCH 08/14] s3:libsmb/clitrans: correctly marshall [nt]trans[s][2] requests We need to align params and data to 4 byte offsets. This also correctly recalculates the useable space after each step. metze (cherry picked from commit 0a8fd50bd806e925a915c74cb86733481b2144f6) --- source3/libsmb/clitrans.c | 53 ++++++++++++++++++++++++++++++++++---------- 1 files changed, 41 insertions(+), 12 deletions(-) diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c index 025ea93..927bacd 100644 --- a/source3/libsmb/clitrans.c +++ b/source3/libsmb/clitrans.c @@ -52,8 +52,9 @@ struct cli_trans_state { struct trans_recvblob rdata; uint16_t recv_flags2; - struct iovec iov[4]; + struct iovec iov[6]; uint8_t pad[4]; + uint8_t zero_pad[4]; uint16_t vwv[32]; }; @@ -173,7 +174,10 @@ static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct, uint16_t *vwv = state->vwv; uint32_t param_offset; uint32_t this_param = 0; + uint32_t param_pad; + uint32_t data_offset; uint32_t this_data = 0; + uint32_t data_pad; uint32_t useable_space; uint8_t cmd; @@ -221,7 +225,18 @@ static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct, break; } - useable_space = state->cli->max_xmit - smb_size - sizeof(uint16_t)*wct; + param_offset += wct * sizeof(uint16_t); + useable_space = state->cli->max_xmit - param_offset; + + param_pad = param_offset % 4; + if (param_pad > 0) { + param_pad = MIN(param_pad, useable_space); + iov[0].iov_base = (void *)state->zero_pad; + iov[0].iov_len = param_pad; + iov += 1; + param_offset += param_pad; + } + useable_space = state->cli->max_xmit - param_offset; if (state->param_sent < state->num_param) { this_param = MIN(state->num_param - state->param_sent, @@ -231,27 +246,41 @@ static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct, iov += 1; } + data_offset = param_offset + this_param; + useable_space = state->cli->max_xmit - data_offset; + + data_pad = data_offset % 4; + if (data_pad > 0) { + data_pad = MIN(data_pad, useable_space); + iov[0].iov_base = (void *)state->zero_pad; + iov[0].iov_len = data_pad; + iov += 1; + data_offset += data_pad; + } + useable_space = state->cli->max_xmit - data_offset; + if (state->data_sent < state->num_data) { this_data = MIN(state->num_data - state->data_sent, - useable_space - this_param); + useable_space); iov[0].iov_base = (void *)(state->data + state->data_sent); iov[0].iov_len = this_data; iov += 1; } - param_offset += wct * sizeof(uint16_t); - DEBUG(10, ("num_setup=%u, max_setup=%u, " "param_total=%u, this_param=%u, max_param=%u, " "data_total=%u, this_data=%u, max_data=%u, " - "param_offset=%u, param_disp=%u, data_disp=%u\n", + "param_offset=%u, param_pad=%u, param_disp=%u, " + "data_offset=%u, data_pad=%u, data_disp=%u\n", (unsigned)state->num_setup, (unsigned)state->max_setup, (unsigned)state->num_param, (unsigned)this_param, (unsigned)state->rparam.max, (unsigned)state->num_data, (unsigned)this_data, (unsigned)state->rdata.max, - (unsigned)param_offset, - (unsigned)state->param_sent, (unsigned)state->data_sent)); + (unsigned)param_offset, (unsigned)param_pad, + (unsigned)state->param_sent, + (unsigned)data_offset, (unsigned)data_pad, + (unsigned)state->data_sent)); switch (cmd) { case SMBtrans: @@ -268,7 +297,7 @@ static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct, SSVAL(vwv + 9, 0, this_param); SSVAL(vwv +10, 0, param_offset); SSVAL(vwv +11, 0, this_data); - SSVAL(vwv +12, 0, param_offset + this_param); + SSVAL(vwv +12, 0, data_offset); SCVAL(vwv +13, 0, state->num_setup); SCVAL(vwv +13, 1, 0); /* reserved */ memcpy(vwv + 14, state->setup, @@ -282,7 +311,7 @@ static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct, SSVAL(vwv + 3, 0, param_offset); SSVAL(vwv + 4, 0, state->param_sent); SSVAL(vwv + 5, 0, this_data); - SSVAL(vwv + 6, 0, param_offset + this_param); + SSVAL(vwv + 6, 0, data_offset); SSVAL(vwv + 7, 0, state->data_sent); if (cmd == SMBtranss2) { SSVAL(vwv + 8, 0, state->fid); @@ -298,7 +327,7 @@ static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct, SIVAL(vwv + 9, 1, this_param); SIVAL(vwv +11, 1, param_offset); SIVAL(vwv +13, 1, this_data); - SIVAL(vwv +15, 1, param_offset + this_param); + SIVAL(vwv +15, 1, data_offset); SCVAL(vwv +17, 1, state->num_setup); SSVAL(vwv +18, 0, state->function); memcpy(vwv + 19, state->setup, @@ -313,7 +342,7 @@ static void cli_trans_format(struct cli_trans_state *state, uint8_t *pwct, SIVAL(vwv + 7, 1, param_offset); SIVAL(vwv + 9, 1, state->param_sent); SIVAL(vwv +11, 1, this_data); - SIVAL(vwv +13, 1, param_offset + this_param); + SIVAL(vwv +13, 1, data_offset); SIVAL(vwv +15, 1, state->data_sent); SCVAL(vwv +17, 1, 0); /* reserved */ break; -- 1.7.4.1 From 942d01bd9d55e8952953ee56fc3c56c0a3e21801 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 16:11:00 +0200 Subject: [PATCH 09/14] s3:libsmb/clitrans: move MID handling to the end of cli_trans_send() and add a comment metze (cherry picked from commit 5146c9ba9df063d6611abe356f9262adb027b091) --- source3/libsmb/clitrans.c | 13 +++++++++++-- 1 files changed, 11 insertions(+), 2 deletions(-) diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c index 927bacd..a3beb64 100644 --- a/source3/libsmb/clitrans.c +++ b/source3/libsmb/clitrans.c @@ -441,14 +441,23 @@ struct tevent_req *cli_trans_send( if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } - state->mid = cli_smb_req_mid(subreq); status = cli_smb_req_send(subreq); if (!NT_STATUS_IS_OK(status)) { tevent_req_nterror(req, status); return tevent_req_post(req, state->ev); } - cli_state_seqnum_persistent(cli, state->mid); tevent_req_set_callback(subreq, cli_trans_done, req); + + /* + * Now get the MID of the primary request + * and mark it as persistent. This means + * we will able to send and receive multiple + * SMB pdus using this MID in both directions + * (including correct SMB signing). + */ + state->mid = cli_smb_req_mid(subreq); + cli_state_seqnum_persistent(cli, state->mid); + return req; } -- 1.7.4.1 From 88cce457062b371f881ee6f6797ce7dbc714e3cb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 16:41:11 +0200 Subject: [PATCH 10/14] s3:libsmb/clitrans: use subreq2 as variable for the secondary requests metze (cherry picked from commit 10bb088cf1e005fd047c09afcf6b5b8999d416fe) --- source3/libsmb/clitrans.c | 16 +++++++++------- 1 files changed, 9 insertions(+), 7 deletions(-) diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c index a3beb64..f450237 100644 --- a/source3/libsmb/clitrans.c +++ b/source3/libsmb/clitrans.c @@ -516,25 +516,27 @@ static void cli_trans_done(struct tevent_req *subreq) if (!sent_all) { int iov_count; + struct tevent_req *subreq2; TALLOC_FREE(subreq); cli_trans_format(state, &wct, &iov_count); - subreq = cli_smb_req_create(state, state->ev, state->cli, - state->cmd + 1, 0, wct, state->vwv, - iov_count, state->iov); - if (tevent_req_nomem(subreq, req)) { + subreq2 = cli_smb_req_create(state, state->ev, state->cli, + state->cmd + 1, 0, wct, state->vwv, + iov_count, state->iov); + if (tevent_req_nomem(subreq2, req)) { return; } - cli_smb_req_set_mid(subreq, state->mid); + cli_smb_req_set_mid(subreq2, state->mid); - status = cli_smb_req_send(subreq); + status = cli_smb_req_send(subreq2); if (!NT_STATUS_IS_OK(status)) { goto fail; } - tevent_req_set_callback(subreq, cli_trans_done, req); + tevent_req_set_callback(subreq2, cli_trans_done2, req); + return; } -- 1.7.4.1 From ae587e96df3bed6bc5e1e7af59504e07c5e2bdc6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 10:31:23 +0200 Subject: [PATCH 11/14] s3:libsmb/clitrans: fix handling of multi pdu [nt]trans[s][2] calls We now keep the primary request open for the whole logical request. The primary request is the one that gets all incoming replies. While secondary requests are handled as separate one-way requests. metze (cherry picked from commit 1dd24ac06a7472f53b06bc0aaa54cb22c8da0f78) --- source3/libsmb/clitrans.c | 88 ++++++++++++++++++++++++++++++++++++++++---- 1 files changed, 80 insertions(+), 8 deletions(-) diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c index f450237..d00851a 100644 --- a/source3/libsmb/clitrans.c +++ b/source3/libsmb/clitrans.c @@ -56,8 +56,26 @@ struct cli_trans_state { uint8_t pad[4]; uint8_t zero_pad[4]; uint16_t vwv[32]; + + struct tevent_req *primary_subreq; }; +static void cli_trans_cleanup_primary(struct cli_trans_state *state) +{ + if (state->primary_subreq) { + cli_smb_req_set_mid(state->primary_subreq, 0); + cli_smb_req_unset_pending(state->primary_subreq); + cli_state_seqnum_remove(state->cli, state->mid); + TALLOC_FREE(state->primary_subreq); + } +} + +static int cli_trans_state_destructor(struct cli_trans_state *state) +{ + cli_trans_cleanup_primary(state); + return 0; +} + static NTSTATUS cli_pull_trans(uint8_t *inbuf, uint8_t wct, uint16_t *vwv, uint16_t num_bytes, uint8_t *bytes, @@ -456,11 +474,16 @@ struct tevent_req *cli_trans_send( * (including correct SMB signing). */ state->mid = cli_smb_req_mid(subreq); + cli_smb_req_set_mid(subreq, state->mid); cli_state_seqnum_persistent(cli, state->mid); + state->primary_subreq = subreq; + talloc_set_destructor(state, cli_trans_state_destructor); return req; } +static void cli_trans_done2(struct tevent_req *subreq); + static void cli_trans_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( @@ -518,8 +541,6 @@ static void cli_trans_done(struct tevent_req *subreq) int iov_count; struct tevent_req *subreq2; - TALLOC_FREE(subreq); - cli_trans_format(state, &wct, &iov_count); subreq2 = cli_smb_req_create(state, state->ev, state->cli, @@ -561,23 +582,72 @@ static void cli_trans_done(struct tevent_req *subreq) if ((state->rparam.total == state->rparam.received) && (state->rdata.total == state->rdata.received)) { state->recv_flags2 = SVAL(inbuf, smb_flg2); - TALLOC_FREE(subreq); - cli_state_seqnum_remove(state->cli, state->mid); + cli_trans_cleanup_primary(state); tevent_req_done(req); return; } TALLOC_FREE(inbuf); - if (!cli_smb_req_set_pending(subreq)) { - status = NT_STATUS_NO_MEMORY; + return; + + fail: + cli_trans_cleanup_primary(state); + tevent_req_nterror(req, status); +} + +static void cli_trans_done2(struct tevent_req *subreq2) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq2, struct tevent_req); + struct cli_trans_state *state = tevent_req_data( + req, struct cli_trans_state); + NTSTATUS status; + bool sent_all; + uint8_t wct; + + status = cli_smb_recv(subreq2, state, NULL, 0, &wct, NULL, + NULL, NULL); + TALLOC_FREE(subreq2); + + if (!NT_STATUS_IS_OK(status)) { goto fail; } + + if (wct != 0) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + sent_all = ((state->param_sent == state->num_param) + && (state->data_sent == state->num_data)); + + if (!sent_all) { + int iov_count; + + cli_trans_format(state, &wct, &iov_count); + + subreq2 = cli_smb_req_create(state, state->ev, state->cli, + state->cmd + 1, 0, wct, state->vwv, + iov_count, state->iov); + if (tevent_req_nomem(subreq2, req)) { + return; + } + cli_smb_req_set_mid(subreq2, state->mid); + + status = cli_smb_req_send(subreq2); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + tevent_req_set_callback(subreq2, cli_trans_done2, req); + return; + } + return; fail: - cli_state_seqnum_remove(state->cli, state->mid); - TALLOC_FREE(subreq); + cli_trans_cleanup_primary(state); tevent_req_nterror(req, status); } @@ -594,6 +664,8 @@ NTSTATUS cli_trans_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, req, struct cli_trans_state); NTSTATUS status; + cli_trans_cleanup_primary(state); + if (tevent_req_is_nterror(req, &status)) { return status; } -- 1.7.4.1 From 6cb8066a77b00323cb0bff5cc494b7b548b211aa Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 9 Jun 2011 11:57:55 +0200 Subject: [PATCH 12/14] s3:libsmb/clitrans: correctly transfer the seqnum between secondary and primary requests This is needed to implement SMB signing correct. metze (cherry picked from commit 5d06b2197b5fd95aaf0394d1bdba957bac6c3570) --- source3/libsmb/clitrans.c | 11 ++++++++--- 1 files changed, 8 insertions(+), 3 deletions(-) diff --git a/source3/libsmb/clitrans.c b/source3/libsmb/clitrans.c index d00851a..3cdb90b 100644 --- a/source3/libsmb/clitrans.c +++ b/source3/libsmb/clitrans.c @@ -32,7 +32,6 @@ struct cli_trans_state { struct event_context *ev; uint8_t cmd; uint16_t mid; - uint32_t seqnum; const char *pipe_name; uint8_t *pipe_name_conv; size_t pipe_name_conv_len; @@ -65,7 +64,6 @@ static void cli_trans_cleanup_primary(struct cli_trans_state *state) if (state->primary_subreq) { cli_smb_req_set_mid(state->primary_subreq, 0); cli_smb_req_unset_pending(state->primary_subreq); - cli_state_seqnum_remove(state->cli, state->mid); TALLOC_FREE(state->primary_subreq); } } @@ -475,7 +473,6 @@ struct tevent_req *cli_trans_send( */ state->mid = cli_smb_req_mid(subreq); cli_smb_req_set_mid(subreq, state->mid); - cli_state_seqnum_persistent(cli, state->mid); state->primary_subreq = subreq; talloc_set_destructor(state, cli_trans_state_destructor); @@ -605,6 +602,14 @@ static void cli_trans_done2(struct tevent_req *subreq2) NTSTATUS status; bool sent_all; uint8_t wct; + uint32_t seqnum; + + /* + * First backup the seqnum of the secondary request + * and attach it to the primary request. + */ + seqnum = cli_smb_req_seqnum(subreq2); + cli_smb_req_set_seqnum(state->primary_subreq, seqnum); status = cli_smb_recv(subreq2, state, NULL, 0, &wct, NULL, NULL, NULL); -- 1.7.4.1 From aadf077b1eacc6c35a241de20865b70ac1612c0e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 18:59:39 +0200 Subject: [PATCH 13/14] s3:libsmb/clireadwrite: calculate cli_read_max_bufsize() correct based on max_xmit This is important in order to support DCERPC over ncacn_np against NT4 servers, where max_xmit is just 4356. metze (cherry picked from commit 73128b7cc7f536f80072a19cb69527c53d9a6c2f) --- source3/libsmb/clireadwrite.c | 13 ++++++++++++- 1 files changed, 12 insertions(+), 1 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 9900d34..6c92c0f 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -28,6 +28,11 @@ ****************************************************************************/ static size_t cli_read_max_bufsize(struct cli_state *cli) { + size_t data_offset = smb_size - 4; + size_t wct = 12; + + size_t useable_space; + if (!client_is_signing_on(cli) && !cli_encryption_on(cli) && (cli->server_posix_capabilities & CIFS_UNIX_LARGE_READ_CAP)) { return CLI_SAMBA_MAX_POSIX_LARGE_READX_SIZE; @@ -37,7 +42,13 @@ static size_t cli_read_max_bufsize(struct cli_state *cli) ? CLI_SAMBA_MAX_LARGE_READX_SIZE : CLI_WINDOWS_MAX_LARGE_READX_SIZE; } - return (cli->max_xmit - (smb_size+32)) & ~1023; + + data_offset += wct * sizeof(uint16_t); + data_offset += 1; /* pad */ + + useable_space = cli->max_xmit - data_offset; + + return useable_space; } /**************************************************************************** -- 1.7.4.1 From 2e72bbcf81c742bdd3323f25c4711fdc0ea9c369 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 19:01:13 +0200 Subject: [PATCH 14/14] s3:libsmb/clireadwrite: calculate cli_write_max_bufsize() correct based on max_xmit This is important in order to support DCERPC over ncacn_np against NT4 servers, where max_xmit is just 4356. metze (cherry picked from commit f0ba1afe5f7dbafaf22c3028864de0f3910f675f) The last 14 patches address the generic part of bug #8195 (rpc client code doesn't work against NT4, when we need to fragment requests). --- source3/libsmb/clireadwrite.c | 20 ++++++++++++-------- 1 files changed, 12 insertions(+), 8 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 6c92c0f..b8af9e5 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -54,7 +54,9 @@ static size_t cli_read_max_bufsize(struct cli_state *cli) /**************************************************************************** Calculate the recommended write buffer size ****************************************************************************/ -static size_t cli_write_max_bufsize(struct cli_state *cli, uint16_t write_mode) +static size_t cli_write_max_bufsize(struct cli_state *cli, + uint16_t write_mode, + uint8_t wct) { if (write_mode == 0 && !client_is_signing_on(cli) && @@ -73,13 +75,15 @@ static size_t cli_write_max_bufsize(struct cli_state *cli, uint16_t write_mode) if (((cli->capabilities & CAP_LARGE_WRITEX) == 0) || client_is_signing_on(cli) || strequal(cli->dev, "LPT1:")) { + size_t data_offset = smb_size - 4; + size_t useable_space; - /* - * Printer devices are restricted to max_xmit writesize in - * Vista and XPSP3 as are signing connections. - */ + data_offset += wct * sizeof(uint16_t); + data_offset += 1; /* pad */ + + useable_space = cli->max_xmit - data_offset; - return (cli->max_xmit - (smb_size+32)) & ~1023; + return useable_space; } return CLI_WINDOWS_MAX_LARGE_WRITEX_SIZE; @@ -799,7 +803,7 @@ struct tevent_req *cli_write_andx_create(TALLOC_CTX *mem_ctx, struct cli_write_andx_state *state; bool bigoffset = ((cli->capabilities & CAP_LARGE_FILES) != 0); uint8_t wct = bigoffset ? 14 : 12; - size_t max_write = cli_write_max_bufsize(cli, mode); + size_t max_write = cli_write_max_bufsize(cli, mode, wct); uint16_t *vwv; req = tevent_req_create(mem_ctx, &state, struct cli_write_andx_state); @@ -1155,7 +1159,7 @@ struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct event_context *ev, state->pending = 0; state->next_offset = start_offset; - state->chunk_size = cli_write_max_bufsize(cli, mode); + state->chunk_size = cli_write_max_bufsize(cli, mode, 14); if (window_size == 0) { window_size = cli->max_mux * state->chunk_size; -- 1.7.4.1