From ccd6d66c0ab4db4ae8215a52d6f591ef95c7d67a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 00:40:54 +0200 Subject: [PATCH 01/15] s3:libsmb/async_smb: let cli_smb_recv() initialize output values for one way requests metze --- 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 2ce6410..45e83b8 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -694,6 +694,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 8fe9e5e4393c0a6f3771b2031c35dc9cfd6da6ad Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 14:14:24 +0200 Subject: [PATCH 02/15] s3:libsmb/async_smb: call cli_smb_req_unset_pending() instead of destructor directly metze --- 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 45e83b8..2e0ddb9 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -627,7 +627,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); @@ -671,7 +671,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 c5acf3c48dadb485c92ed5e9a397d305d67386f8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 10:20:25 +0200 Subject: [PATCH 03/15] 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 --- 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 2e0ddb9..c09a886 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -153,6 +153,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 @@ -193,6 +201,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 d7b1d6bca7a73307cf1e351af64e39ce3da1316f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 9 Jun 2011 11:49:48 +0200 Subject: [PATCH 04/15] 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 --- 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 c09a886..145e0ae 100644 --- a/source3/libsmb/async_smb.c +++ b/source3/libsmb/async_smb.c @@ -270,6 +270,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 7b9b0635b6843d02e6c2a749c755d1b58bc7f683 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 00:37:24 +0200 Subject: [PATCH 05/15] s3:libsmb/clitrans: remove unused secondary_request_ctx metze --- 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 99a358f..e53f51b 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 4ab5e7b9a47a650fbc7d1f2efcd2c40a29378186 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 17:08:00 +0200 Subject: [PATCH 06/15] s3:libsmb/clitrans: use uint32_t for param and data variables SMBnttrans uses 32-bit values there. metze --- 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 e53f51b..8017948 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 27dfd48a5aaf68111aa30110ee8a83a769d2dfc4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 9 Jun 2011 12:22:59 +0200 Subject: [PATCH 07/15] 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 --- 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 8017948..d8cd8e8 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 1b0108d33d41072f3f654d96e202a9b859a7ca0b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 00:44:34 +0200 Subject: [PATCH 08/15] 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 --- 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 d8cd8e8..cf6809b 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 d8f19cf3c5d63e1a1ff476285e45712013e8b8ee Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 16:11:00 +0200 Subject: [PATCH 09/15] s3:libsmb/clitrans: move MID handling to the end of cli_trans_send() and add a comment metze --- 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 cf6809b..82a73ee 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 39ee9849dd7ee33ea819fc6745794994e96f584d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 16:41:11 +0200 Subject: [PATCH 10/15] s3:libsmb/clitrans: use subreq2 as variable for the secondary requests metze --- 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 82a73ee..cf1f725 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 42d0e3f569c3770e62b1831fc175d454a4301e66 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 10:31:23 +0200 Subject: [PATCH 11/15] 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 --- 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 cf1f725..e23598c 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 f726c0a8fb00b3cbd2e76d9d22bd52f9d90ed73e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 9 Jun 2011 11:57:55 +0200 Subject: [PATCH 12/15] s3:libsmb/clitrans: correctly transfer the seqnum between secondary and primary requests This is needed to implement SMB signing correct. metze --- 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 e23598c..dd8063b 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 68ab9dec0e9bb513dfd14722a95c5847e294c80b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 18:59:39 +0200 Subject: [PATCH 13/15] 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 --- 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 c19151e..e8baeba 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 cf76a6bc010ea4ac60286b31f66060f1644598ce Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 8 Jun 2011 19:01:13 +0200 Subject: [PATCH 14/15] 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 --- 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 e8baeba..14b6401 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; @@ -795,7 +799,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); @@ -1148,7 +1152,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 From 6ce3aa061635e497f6297eac7c6908872c4d817c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Thu, 9 Jun 2011 11:59:58 +0200 Subject: [PATCH 15/15] s3:libsmb: remove unused cli_state_seqnum infrastructure metze --- source3/include/client.h | 8 -------- source3/libsmb/clientgen.c | 32 -------------------------------- source3/libsmb/proto.h | 4 ---- 3 files changed, 0 insertions(+), 44 deletions(-) diff --git a/source3/include/client.h b/source3/include/client.h index 7d66bf9..a853e90 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -46,13 +46,6 @@ struct print_job_info { time_t t; }; -struct cli_state_seqnum { - struct cli_state_seqnum *prev, *next; - uint16_t mid; - uint32_t seqnum; - bool persistent; -}; - struct cli_state { /** * A list of subsidiary connections for DFS. @@ -103,7 +96,6 @@ struct cli_state { size_t max_xmit; size_t max_mux; char *outbuf; - struct cli_state_seqnum *seqnum; char *inbuf; unsigned int bufsize; int initialised; diff --git a/source3/libsmb/clientgen.c b/source3/libsmb/clientgen.c index 1122bbb..d3b66b6 100644 --- a/source3/libsmb/clientgen.c +++ b/source3/libsmb/clientgen.c @@ -68,37 +68,6 @@ bool cli_ucs2(struct cli_state *cli) return ((cli->capabilities & CAP_UNICODE) != 0); } -bool cli_state_seqnum_persistent(struct cli_state *cli, - uint16_t mid) -{ - struct cli_state_seqnum *c; - - for (c = cli->seqnum; c; c = c->next) { - if (c->mid == mid) { - c->persistent = true; - return true; - } - } - - return false; -} - -bool cli_state_seqnum_remove(struct cli_state *cli, - uint16_t mid) -{ - struct cli_state_seqnum *c; - - for (c = cli->seqnum; c; c = c->next) { - if (c->mid == mid) { - DLIST_REMOVE(cli->seqnum, c); - TALLOC_FREE(c); - return true; - } - } - - return false; -} - /**************************************************************************** Setup basics in a outgoing packet. ****************************************************************************/ @@ -233,7 +202,6 @@ struct cli_state *cli_initialise_ex(int signing_state) cli->bufsize = CLI_BUFFER_SIZE+4; cli->max_xmit = cli->bufsize; cli->outbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN); - cli->seqnum = 0; cli->inbuf = (char *)SMB_MALLOC(cli->bufsize+SAFETY_MARGIN); cli->oplock_handler = cli_oplock_ack; cli->case_sensitive = false; diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index 37a928e..2b32c10 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -146,10 +146,6 @@ bool cli_check_msdfs_proxy(TALLOC_CTX *ctx, int cli_set_message(char *buf,int num_words,int num_bytes,bool zero); unsigned int cli_set_timeout(struct cli_state *cli, unsigned int timeout); void cli_set_port(struct cli_state *cli, int port); -bool cli_state_seqnum_persistent(struct cli_state *cli, - uint16_t mid); -bool cli_state_seqnum_remove(struct cli_state *cli, - uint16_t mid); void cli_setup_packet_buf(struct cli_state *cli, char *buf); NTSTATUS cli_set_domain(struct cli_state *cli, const char *domain); NTSTATUS cli_set_username(struct cli_state *cli, const char *username); -- 1.7.4.1