diff --git a/samba-4.0.4-fix_large_read_handling.patch b/samba-4.0.4-fix_large_read_handling.patch new file mode 100644 index 0000000..b4c3b19 --- /dev/null +++ b/samba-4.0.4-fix_large_read_handling.patch @@ -0,0 +1,1172 @@ +From 73d7c14fadeb735c51d9039375b40b21950f9fcf Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 19 Mar 2013 09:02:52 +0100 +Subject: [PATCH 01/16] libcli/smb: add SMB_CAP_LEGACY_CLIENT_MASK define + +Older Samba releases (<= 3.6.x) +expect the client to send CAP_LARGE_READX +in order to let the client use large reads. + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Jeremy Allison +--- + libcli/smb/smb_constants.h | 10 ++++++++++ + 1 file changed, 10 insertions(+) + +diff --git a/libcli/smb/smb_constants.h b/libcli/smb/smb_constants.h +index 8cb3b6e..bcfd84e 100644 +--- a/libcli/smb/smb_constants.h ++++ b/libcli/smb/smb_constants.h +@@ -253,6 +253,16 @@ enum smb_signing_setting { + #define SMB_CAP_CLIENT_MASK ( \ + CAP_DYNAMIC_REAUTH | \ + 0) ++/* ++ * Older Samba releases (<= 3.6.x) ++ * expect the client to send CAP_LARGE_READX ++ * in order to let the client use large reads. ++ */ ++#define SMB_CAP_LEGACY_CLIENT_MASK ( \ ++ SMB_CAP_CLIENT_MASK | \ ++ CAP_LARGE_READX | \ ++ CAP_LARGE_WRITEX | \ ++ 0) + + /* Client-side offline caching policy types */ + enum csc_policy { +-- +1.8.1.3 + + +From 1b24d5d7e15ee40509f81ae64893f38b9ed7f5cb Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 19 Mar 2013 09:03:38 +0100 +Subject: [PATCH 02/16] s3:libsmb: make use of SMB_CAP_LEGACY_CLIENT_MASK + instead of SMB_CAP_CLIENT_MASK + +This should allow smbclient to keep using large reads against older Samba versions +(<= 3.6.x) and other servers that may also require this. + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Jeremy Allison +--- + source3/libsmb/cliconnect.c | 8 ++++++-- + 1 file changed, 6 insertions(+), 2 deletions(-) + +diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c +index 9ce013e..d1e161f 100644 +--- a/source3/libsmb/cliconnect.c ++++ b/source3/libsmb/cliconnect.c +@@ -341,9 +341,13 @@ static uint32_t cli_session_setup_capabilities(struct cli_state *cli, + * - client only flags + * - flags used in both directions + * +- * We do not echo the server only flags. ++ * We do not echo the server only flags, except some legacy flags. ++ * ++ * SMB_CAP_LEGACY_CLIENT_MASK contains CAP_LARGE_READX and ++ * CAP_LARGE_WRITEX in order to allow us to do large reads ++ * against old Samba releases (<= 3.6.x). + */ +- client_capabilities &= (SMB_CAP_BOTH_MASK | SMB_CAP_CLIENT_MASK); ++ client_capabilities &= (SMB_CAP_BOTH_MASK | SMB_CAP_LEGACY_CLIENT_MASK); + + /* + * Session Setup specific flags CAP_DYNAMIC_REAUTH +-- +1.8.1.3 + + +From 705f9c20aa1f37a9af5c181d113957ce99deb5fe Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 18 Mar 2013 15:02:55 +0100 +Subject: [PATCH 03/16] libcli/smb: defer failing for missing + NEGOTIATE_SECURITY_SIGNATURES_ENABLED + +Windows servers take a look at the FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED +flag during a session setup and turn on signing if the client requires it. + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Jeremy Allison +--- + libcli/smb/smbXcli_base.c | 9 +++++++++ + 1 file changed, 9 insertions(+) + +diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c +index c547515..2523dfb 100644 +--- a/libcli/smb/smbXcli_base.c ++++ b/libcli/smb/smbXcli_base.c +@@ -4046,6 +4046,15 @@ static void smbXcli_negprot_smb1_done(struct tevent_req *subreq) + if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_ENABLED) { + server_signing = "supported"; + server_allowed = true; ++ } else if (conn->mandatory_signing) { ++ /* ++ * We have mandatory signing as client ++ * lets assume the server will look at our ++ * FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED ++ * flag in the session setup ++ */ ++ server_signing = "not announced"; ++ server_allowed = true; + } + if (server_security_mode & NEGOTIATE_SECURITY_SIGNATURES_REQUIRED) { + server_signing = "required"; +-- +1.8.1.3 + + +From 6cbbf63036cae745fcd0a27190c459e71ed3ce48 Mon Sep 17 00:00:00 2001 +From: Jeremy Allison +Date: Wed, 13 Mar 2013 15:23:52 -0700 +Subject: [PATCH 04/16] libcli/smb: smb1cli_inbuf_parse_chain() and + smb1cli_conn_dispatch_incoming() should use smb_len_tcp. + +They have to cope with large READX call replies that have +a length greater than smb_len_nbt() can handle. + +Signed-off-by: Jeremy Allison +Reviewed-by: Stefan Metzmacher +--- + libcli/smb/smbXcli_base.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c +index 2523dfb..c971a6d 100644 +--- a/libcli/smb/smbXcli_base.c ++++ b/libcli/smb/smbXcli_base.c +@@ -1618,7 +1618,7 @@ static NTSTATUS smb1cli_inbuf_parse_chain(uint8_t *buf, TALLOC_CTX *mem_ctx, + NTSTATUS status; + size_t min_size = MIN_SMB_SIZE; + +- buflen = smb_len_nbt(buf); ++ buflen = smb_len_tcp(buf); + taken = 0; + + hdr = buf + NBT_HDR_SIZE; +@@ -1845,7 +1845,7 @@ static NTSTATUS smb1cli_conn_dispatch_incoming(struct smbXcli_conn *conn, + uint16_t mid; + bool oplock_break; + uint8_t *inhdr = inbuf + NBT_HDR_SIZE; +- size_t len = smb_len_nbt(inbuf); ++ size_t len = smb_len_tcp(inbuf); + struct iovec *iov = NULL; + int num_iov = 0; + struct tevent_req **chain = NULL; +-- +1.8.1.3 + + +From c6f8bbaa0a8d9c0c8fe60dfd304ae8bc39d2c554 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 18 Mar 2013 09:33:00 +0100 +Subject: [PATCH 05/16] s3:libsmb: let cli_read_andx_create() accept any length + +It's up to the server to decide the allowed length. + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Jeremy Allison +--- + source3/libsmb/clireadwrite.c | 7 ------- + 1 file changed, 7 deletions(-) + +diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c +index 3cc6cf8..c429d30 100644 +--- a/source3/libsmb/clireadwrite.c ++++ b/source3/libsmb/clireadwrite.c +@@ -132,13 +132,6 @@ struct tevent_req *cli_read_andx_create(TALLOC_CTX *mem_ctx, + struct cli_read_andx_state *state; + uint8_t wct = 10; + +- if (size > cli_read_max_bufsize(cli)) { +- DEBUG(0, ("cli_read_andx_send got size=%d, can only handle " +- "size=%d\n", (int)size, +- (int)cli_read_max_bufsize(cli))); +- return NULL; +- } +- + req = tevent_req_create(mem_ctx, &state, struct cli_read_andx_state); + if (req == NULL) { + return NULL; +-- +1.8.1.3 + + +From 1a596a7b46d89489f94ed970cea3ed6eb105cc92 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 18 Mar 2013 10:10:25 +0100 +Subject: [PATCH 06/16] s3:smbd: keep global_client_caps and max_send from the + first successful session setup + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Jeremy Allison +--- + source3/smbd/sesssetup.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/source3/smbd/sesssetup.c b/source3/smbd/sesssetup.c +index 890189c..4728759 100644 +--- a/source3/smbd/sesssetup.c ++++ b/source3/smbd/sesssetup.c +@@ -132,11 +132,12 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) + uint16_t action = 0; + NTTIME now = timeval_to_nttime(&req->request_time); + struct smbXsrv_session *session = NULL; ++ uint16_t smb_bufsize = SVAL(req->vwv+2, 0); + uint32_t client_caps = IVAL(req->vwv+10, 0); + + DEBUG(3,("Doing spnego session setup\n")); + +- if (global_client_caps == 0) { ++ if (!sconn->smb1.sessions.done_sesssetup) { + global_client_caps = client_caps; + + if (!(global_client_caps & CAP_STATUS32)) { +@@ -377,6 +378,12 @@ static void reply_sesssetup_and_X_spnego(struct smb_request *req) + return; + } + ++ if (!sconn->smb1.sessions.done_sesssetup) { ++ sconn->smb1.sessions.max_send = ++ MIN(sconn->smb1.sessions.max_send,smb_bufsize); ++ } ++ sconn->smb1.sessions.done_sesssetup = true; ++ + /* current_user_info is changed on new vuid */ + reload_services(sconn, conn_snum_used, true); + } else if (NT_STATUS_IS_OK(status)) { +@@ -560,7 +567,7 @@ static void setup_new_vc_session(struct smbd_server_connection *sconn) + void reply_sesssetup_and_X(struct smb_request *req) + { + uint64_t sess_vuid; +- int smb_bufsize; ++ uint16_t smb_bufsize; + DATA_BLOB lm_resp; + DATA_BLOB nt_resp; + DATA_BLOB plaintext_password; +@@ -671,8 +678,7 @@ void reply_sesssetup_and_X(struct smb_request *req) + const uint8_t *save_p = req->buf; + uint16 byte_count; + +- +- if(global_client_caps == 0) { ++ if (!sconn->smb1.sessions.done_sesssetup) { + global_client_caps = IVAL(req->vwv+11, 0); + + if (!(global_client_caps & CAP_STATUS32)) { +-- +1.8.1.3 + + +From 8b805f9a8fb692691c8a85971edb55bd0b3fb0c0 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 19 Mar 2013 13:24:46 +0100 +Subject: [PATCH 07/16] s3:smbd: remove silly (SMB_OFF_T_BITS == 64) checks + +configure will abort if sizeof(off_t) is not 8. + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Jeremy Allison +--- + source3/smbd/negprot.c | 5 ++--- + 1 file changed, 2 insertions(+), 3 deletions(-) + +diff --git a/source3/smbd/negprot.c b/source3/smbd/negprot.c +index e33350c..cfe0983 100644 +--- a/source3/smbd/negprot.c ++++ b/source3/smbd/negprot.c +@@ -284,11 +284,10 @@ static void reply_nt1(struct smb_request *req, uint16 choice) + capabilities |= CAP_UNIX; + } + +- if (lp_large_readwrite() && (SMB_OFF_T_BITS == 64)) ++ if (lp_large_readwrite()) + capabilities |= CAP_LARGE_READX|CAP_LARGE_WRITEX|CAP_W2K_SMBS; + +- if (SMB_OFF_T_BITS == 64) +- capabilities |= CAP_LARGE_FILES; ++ capabilities |= CAP_LARGE_FILES; + + if (lp_readraw() && lp_writeraw()) + capabilities |= CAP_RAW_MODE; +-- +1.8.1.3 + + +From 804f5749f8622768ac7e4925fc78bcd07f9fe234 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 18 Mar 2013 12:36:30 +0100 +Subject: [PATCH 08/16] s3:smbd: add some const to req_is_in_chain() + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Jeremy Allison +--- + source3/smbd/process.c | 2 +- + source3/smbd/proto.h | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/source3/smbd/process.c b/source3/smbd/process.c +index e934eaa..43bf76e 100644 +--- a/source3/smbd/process.c ++++ b/source3/smbd/process.c +@@ -3631,7 +3631,7 @@ void smbd_process(struct tevent_context *ev_ctx, + exit_server_cleanly(NULL); + } + +-bool req_is_in_chain(struct smb_request *req) ++bool req_is_in_chain(const struct smb_request *req) + { + if (req->vwv != (const uint16_t *)(req->inbuf+smb_vwv)) { + /* +diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h +index fae1407..35ae8a2 100644 +--- a/source3/smbd/proto.h ++++ b/source3/smbd/proto.h +@@ -786,7 +786,7 @@ bool smb1_parse_chain(TALLOC_CTX *mem_ctx, const uint8_t *buf, + struct smbd_server_connection *sconn, + bool encrypted, uint32_t seqnum, + struct smb_request ***reqs, unsigned *num_reqs); +-bool req_is_in_chain(struct smb_request *req); ++bool req_is_in_chain(const struct smb_request *req); + void smbd_process(struct tevent_context *ev_ctx, + struct messaging_context *msg_ctx, + int sock_fd, +-- +1.8.1.3 + + +From 77cb710192e1a0bd6204a0a87ad3642e59c040a6 Mon Sep 17 00:00:00 2001 +From: Jeremy Allison +Date: Mon, 18 Mar 2013 15:05:24 -0700 +Subject: [PATCH 09/16] s3:smbd: Fix off-by 4 error in wrap protection code in + create_outbuf() + +Subtract 4 from smb_size (39) here as the length +of the SMB reply following the 4 byte type+length +field can be up to 0xFFFFFF bytes. + +Signed-off-by: Jeremy Allison +Signed-off-by: Stefan Metzmacher +Reviewed-by: Stefan Metzmacher +--- + source3/smbd/process.c | 17 +++++++++++------ + 1 file changed, 11 insertions(+), 6 deletions(-) + +diff --git a/source3/smbd/process.c b/source3/smbd/process.c +index 43bf76e..f03a20f 100644 +--- a/source3/smbd/process.c ++++ b/source3/smbd/process.c +@@ -1270,11 +1270,13 @@ static bool create_outbuf(TALLOC_CTX *mem_ctx, struct smb_request *req, + const char *inbuf, char **outbuf, uint8_t num_words, + uint32_t num_bytes) + { ++ size_t smb_len = MIN_SMB_SIZE + VWV(num_words) + num_bytes; ++ + /* +- * Protect against integer wrap +- */ +- if ((num_bytes > 0xffffff) +- || ((num_bytes + smb_size + num_words*2) > 0xffffff)) { ++ * Protect against integer wrap. ++ * The SMB layer reply can be up to 0xFFFFFF bytes. ++ */ ++ if ((num_bytes > 0xffffff) || (smb_len > 0xffffff)) { + char *msg; + if (asprintf(&msg, "num_bytes too large: %u", + (unsigned)num_bytes) == -1) { +@@ -1283,8 +1285,11 @@ static bool create_outbuf(TALLOC_CTX *mem_ctx, struct smb_request *req, + smb_panic(msg); + } + ++ /* ++ * Here we include the NBT header for now. ++ */ + *outbuf = talloc_array(mem_ctx, char, +- smb_size + num_words*2 + num_bytes); ++ NBT_HDR_SIZE + smb_len); + if (*outbuf == NULL) { + return false; + } +@@ -1296,7 +1301,7 @@ static bool create_outbuf(TALLOC_CTX *mem_ctx, struct smb_request *req, + * himself + */ + if (num_words != 0) { +- memset(*outbuf + smb_vwv0, 0, num_words*2); ++ memset(*outbuf + (NBT_HDR_SIZE + HDR_VWV), 0, VWV(num_words)); + } + + return true; +-- +1.8.1.3 + + +From 3e9234b1ec071457e3f03f2270b6d778c66df2e0 Mon Sep 17 00:00:00 2001 +From: Jeremy Allison +Date: Fri, 15 Mar 2013 11:53:04 -0700 +Subject: [PATCH 10/16] s3:smbd: Remove server_will_accept_large_read() and + erroneous comment. + +We're going to replace this with a function that calculates +the max PDU to return on a read and supports short reads. + +Signed-off-by: Jeremy Allison +Reviewed-by: Stefan Metzmacher +--- + source3/smbd/reply.c | 29 +---------------------------- + 1 file changed, 1 insertion(+), 28 deletions(-) + +diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c +index 1c5627c..ffc5ff7 100644 +--- a/source3/smbd/reply.c ++++ b/source3/smbd/reply.c +@@ -3848,26 +3848,6 @@ nosendfile_read: + } + + /**************************************************************************** +- MacOSX clients send large reads without telling us they are going to do that. +- Bug #9572 - File corruption during SMB1 read by Mac OSX 10.8.2 clients +- Allow this if we are talking to a Samba client, or if we told the client +- we supported this. +-****************************************************************************/ +- +-static bool server_will_accept_large_read(void) +-{ +- /* Samba client ? No problem. */ +- if (get_remote_arch() == RA_SAMBA) { +- return true; +- } +- /* Need UNIX extensions. */ +- if (!lp_unix_extensions()) { +- return false; +- } +- return true; +-} +- +-/**************************************************************************** + Reply to a read and X. + ****************************************************************************/ + +@@ -3913,14 +3893,7 @@ void reply_read_and_X(struct smb_request *req) + } + + upper_size = SVAL(req->vwv+7, 0); +- if ((upper_size != 0) && server_will_accept_large_read()) { +- /* +- * This is Samba only behavior (up to Samba 3.6)! +- * +- * Windows 2008 R2 ignores the upper_size, +- * so we do unless unix extentions are active +- * or "smbclient" is talking to us. +- */ ++ if (upper_size != 0) { + smb_maxcnt |= (upper_size<<16); + if (upper_size > 1) { + /* Can't do this on a chained packet. */ +-- +1.8.1.3 + + +From 9b5751b4ae77ac6a46820350377b26765ca8844f Mon Sep 17 00:00:00 2001 +From: Jeremy Allison +Date: Fri, 15 Mar 2013 11:57:48 -0700 +Subject: [PATCH 11/16] s3:smbd: Add functions + calc_max_read_pdu()/calc_read_size() to work out the length we should return. + +LARGE_READX test shows it's always safe to return a short read. +Windows does so. Do the calculations to return what will fit +in a read depending on what the client negotiated. + +Signed-off-by: Jeremy Allison +Signed-off-by: Stefan Metzmacher +Reviewed-by: Stefan Metzmacher +--- + source3/smbd/reply.c | 111 +++++++++++++++++++++++++++++++++++++++------------ + 1 file changed, 86 insertions(+), 25 deletions(-) + +diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c +index ffc5ff7..2326015 100644 +--- a/source3/smbd/reply.c ++++ b/source3/smbd/reply.c +@@ -3848,6 +3848,84 @@ nosendfile_read: + } + + /**************************************************************************** ++ Work out how much space we have for a read return. ++****************************************************************************/ ++ ++static size_t calc_max_read_pdu(const struct smb_request *req) ++{ ++ if (req->sconn->conn->protocol < PROTOCOL_NT1) { ++ return req->sconn->smb1.sessions.max_send; ++ } ++ ++ if (!lp_large_readwrite()) { ++ return req->sconn->smb1.sessions.max_send; ++ } ++ ++ if (req_is_in_chain(req)) { ++ return req->sconn->smb1.sessions.max_send; ++ } ++ ++ if (req->encrypted) { ++ /* ++ * Don't take encrypted traffic up to the ++ * limit. There are padding considerations ++ * that make that tricky. ++ */ ++ return req->sconn->smb1.sessions.max_send; ++ } ++ ++ if (srv_is_signing_active(req->sconn)) { ++ return 0x1FFFF; ++ } ++ ++ if (!lp_unix_extensions()) { ++ return 0x1FFFF; ++ } ++ ++ /* ++ * We can do ultra-large POSIX reads. ++ */ ++ return 0xFFFFFF; ++} ++ ++/**************************************************************************** ++ Calculate how big a read can be. Copes with all clients. It's always ++ safe to return a short read - Windows does this. ++****************************************************************************/ ++ ++static size_t calc_read_size(const struct smb_request *req, ++ size_t upper_size, ++ size_t lower_size) ++{ ++ size_t max_pdu = calc_max_read_pdu(req); ++ size_t total_size = 0; ++ size_t hdr_len = MIN_SMB_SIZE + VWV(12); ++ size_t max_len = max_pdu - hdr_len; ++ ++ /* ++ * Windows explicitly ignores upper size of 0xFFFF. ++ * See [MS-SMB].pdf <26> Section 2.2.4.2.1: ++ * We must do the same as these will never fit even in ++ * an extended size NetBIOS packet. ++ */ ++ if (upper_size == 0xFFFF) { ++ upper_size = 0; ++ } ++ ++ if (req->sconn->conn->protocol < PROTOCOL_NT1) { ++ upper_size = 0; ++ } ++ ++ total_size = ((upper_size<<16) | lower_size); ++ ++ /* ++ * LARGE_READX test shows it's always safe to return ++ * a short read. Windows does so. ++ */ ++ return MIN(total_size, max_len); ++} ++ ++/**************************************************************************** + Reply to a read and X. + ****************************************************************************/ + +@@ -3893,31 +3971,14 @@ void reply_read_and_X(struct smb_request *req) + } + + upper_size = SVAL(req->vwv+7, 0); +- if (upper_size != 0) { +- smb_maxcnt |= (upper_size<<16); +- if (upper_size > 1) { +- /* Can't do this on a chained packet. */ +- if ((CVAL(req->vwv+0, 0) != 0xFF)) { +- reply_nterror(req, NT_STATUS_NOT_SUPPORTED); +- END_PROFILE(SMBreadX); +- return; +- } +- /* We currently don't do this on signed or sealed data. */ +- if (srv_is_signing_active(req->sconn) || +- is_encrypted_packet(req->sconn, req->inbuf)) { +- reply_nterror(req, NT_STATUS_NOT_SUPPORTED); +- END_PROFILE(SMBreadX); +- return; +- } +- /* Is there room in the reply for this data ? */ +- if (smb_maxcnt > (0xFFFFFF - (smb_size -4 + 12*2))) { +- reply_nterror(req, +- NT_STATUS_INVALID_PARAMETER); +- END_PROFILE(SMBreadX); +- return; +- } +- big_readX = True; +- } ++ smb_maxcnt = calc_read_size(req, upper_size, smb_maxcnt); ++ if (smb_maxcnt > (0x1FFFF - (MIN_SMB_SIZE + VWV(12)))) { ++ /* ++ * This is a heuristic to avoid keeping large ++ * outgoing buffers around over long-lived aio ++ * requests. ++ */ ++ big_readX = True; + } + + if (req->wct == 12) { +-- +1.8.1.3 + + +From 608106f67a4f411dba096d104a9258401a67211c Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Mon, 18 Mar 2013 19:50:38 +0100 +Subject: [PATCH 12/16] s4:smb_server: fix large read_andx requests + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Jeremy Allison +--- + source4/smb_server/smb/reply.c | 18 ++++++++++++------ + 1 file changed, 12 insertions(+), 6 deletions(-) + +diff --git a/source4/smb_server/smb/reply.c b/source4/smb_server/smb/reply.c +index bae6b2c..7ce5f5d 100644 +--- a/source4/smb_server/smb/reply.c ++++ b/source4/smb_server/smb/reply.c +@@ -848,6 +848,7 @@ static void reply_read_and_X_send(struct ntvfs_request *ntvfs) + void smbsrv_reply_read_and_X(struct smbsrv_request *req) + { + union smb_read *io; ++ uint16_t high_part = 0; + + /* parse request */ + if (req->in.wct != 12) { +@@ -869,13 +870,18 @@ void smbsrv_reply_read_and_X(struct smbsrv_request *req) + io->readx.in.read_for_execute = false; + } + +- if (req->smb_conn->negotiate.client_caps & CAP_LARGE_READX) { +- uint32_t high_part = IVAL(req->in.vwv, VWV(7)); +- if (high_part == 1) { +- io->readx.in.maxcnt |= high_part << 16; +- } ++ if (req->smb_conn->negotiate.protocol == PROTOCOL_NT1) { ++ high_part = SVAL(req->in.vwv, VWV(7)); + } +- ++ if (high_part != UINT16_MAX) { ++ io->readx.in.maxcnt |= high_part << 16; ++ } ++ ++ /* ++ * Windows truncates the length to 0x10000 ++ */ ++ io->readx.in.maxcnt = MIN(io->readx.in.maxcnt, 0x10000); ++ + /* the 64 bit variant */ + if (req->in.wct == 12) { + uint32_t offset_high = IVAL(req->in.vwv, VWV(10)); +-- +1.8.1.3 + + +From 822e7d7d8c84c8b756e13c00dc870a7964ac54cc Mon Sep 17 00:00:00 2001 +From: Jeremy Allison +Date: Wed, 13 Mar 2013 15:43:21 -0700 +Subject: [PATCH 13/16] s3:torture: Add new LARGE_READX test to investigate + large SMBreadX behavior. + +Signed-off-by: Jeremy Allison +Signed-off-by: Stefan Metzmacher +Reviewed-by: Stefan Metzmacher +--- + source3/torture/torture.c | 338 +++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 337 insertions(+), 1 deletion(-) + +diff --git a/source3/torture/torture.c b/source3/torture/torture.c +index cd885a1..21dcf9b 100644 +--- a/source3/torture/torture.c ++++ b/source3/torture/torture.c +@@ -65,7 +65,7 @@ static fstring multishare_conn_fname; + static bool use_multishare_conn = False; + static bool do_encrypt; + static const char *local_path = NULL; +-static int signing_state = SMB_SIGNING_DEFAULT; ++static enum smb_signing_setting signing_state = SMB_SIGNING_DEFAULT; + char *test_filename; + + bool torture_showall = False; +@@ -7237,6 +7237,341 @@ static bool run_windows_write(int dummy) + return ret; + } + ++static size_t calc_expected_return(struct cli_state *cli, size_t len_requested) ++{ ++ size_t max_pdu = 0x1FFFF; ++ ++ if (cli->server_posix_capabilities & CIFS_UNIX_LARGE_READ_CAP) { ++ max_pdu = 0xFFFFFF; ++ } ++ ++ if (smb1cli_conn_signing_is_active(cli->conn)) { ++ max_pdu = 0x1FFFF; ++ } ++ ++ if (smb1cli_conn_encryption_on(cli->conn)) { ++ max_pdu = CLI_BUFFER_SIZE; ++ } ++ ++ if ((len_requested & 0xFFFF0000) == 0xFFFF0000) { ++ len_requested &= 0xFFFF; ++ } ++ ++ return MIN(len_requested, max_pdu - (MIN_SMB_SIZE + VWV(12))); ++} ++ ++static bool check_read_call(struct cli_state *cli, ++ uint16_t fnum, ++ uint8_t *buf, ++ size_t len_requested) ++{ ++ NTSTATUS status; ++ struct tevent_req *subreq = NULL; ++ ssize_t len_read = 0; ++ size_t len_expected = 0; ++ struct tevent_context *ev = NULL; ++ ++ ev = tevent_context_init(talloc_tos()); ++ if (ev == NULL) { ++ return false; ++ } ++ ++ subreq = cli_read_andx_send(talloc_tos(), ++ ev, ++ cli, ++ fnum, ++ 0, ++ len_requested); ++ ++ if (!tevent_req_poll_ntstatus(subreq, ev, &status)) { ++ return false; ++ } ++ ++ status = cli_read_andx_recv(subreq, &len_read, &buf); ++ if (!NT_STATUS_IS_OK(status)) { ++ d_printf("cli_read_andx_recv failed: %s\n", nt_errstr(status)); ++ return false; ++ } ++ ++ TALLOC_FREE(subreq); ++ TALLOC_FREE(ev); ++ ++ len_expected = calc_expected_return(cli, len_requested); ++ ++ if (len_expected > 0x10000 && len_read == 0x10000) { ++ /* Windows servers only return a max of 0x10000, ++ doesn't matter if you set CAP_LARGE_READX in ++ the client sessionsetupX call or not. */ ++ d_printf("Windows server - returned 0x10000 on a read of 0x%x\n", ++ (unsigned int)len_requested); ++ } else if (len_read != len_expected) { ++ d_printf("read of 0x%x failed: got 0x%x, expected 0x%x\n", ++ (unsigned int)len_requested, ++ (unsigned int)len_read, ++ (unsigned int)len_expected); ++ return false; ++ } else { ++ d_printf("Correct read reply.\n"); ++ } ++ ++ return true; ++} ++ ++/* Test large readX variants. */ ++static bool large_readx_tests(struct cli_state *cli, ++ uint16_t fnum, ++ uint8_t *buf) ++{ ++ /* A read of 0xFFFF0001 should *always* return 1 byte. */ ++ if (check_read_call(cli, fnum, buf, 0xFFFF0001) == false) { ++ return false; ++ } ++ /* A read of 0x10000 should return 0x10000 bytes. */ ++ if (check_read_call(cli, fnum, buf, 0x10000) == false) { ++ return false; ++ } ++ /* A read of 0x10000 should return 0x10001 bytes. */ ++ if (check_read_call(cli, fnum, buf, 0x10001) == false) { ++ return false; ++ } ++ /* A read of 0x1FFFF - (MIN_SMB_SIZE + VWV(12) should return ++ the requested number of bytes. */ ++ if (check_read_call(cli, fnum, buf, 0x1FFFF - (MIN_SMB_SIZE + VWV(12))) == false) { ++ return false; ++ } ++ /* A read of 1MB should return 1MB bytes (on Samba). */ ++ if (check_read_call(cli, fnum, buf, 0x100000) == false) { ++ return false; ++ } ++ ++ if (check_read_call(cli, fnum, buf, 0x20001) == false) { ++ return false; ++ } ++ if (check_read_call(cli, fnum, buf, 0x22000001) == false) { ++ return false; ++ } ++ if (check_read_call(cli, fnum, buf, 0xFFFE0001) == false) { ++ return false; ++ } ++ return true; ++} ++ ++static bool run_large_readx(int dummy) ++{ ++ uint8_t *buf = NULL; ++ struct cli_state *cli1 = NULL; ++ struct cli_state *cli2 = NULL; ++ bool correct = false; ++ const char *fname = "\\large_readx.dat"; ++ NTSTATUS status; ++ uint16_t fnum1 = UINT16_MAX; ++ uint32_t normal_caps = 0; ++ size_t file_size = 20*1024*1024; ++ TALLOC_CTX *frame = talloc_stackframe(); ++ size_t i; ++ struct { ++ const char *name; ++ enum smb_signing_setting signing_setting; ++ enum protocol_types protocol; ++ } runs[] = { ++ { ++ .name = "NT1", ++ .signing_setting = SMB_SIGNING_IF_REQUIRED, ++ .protocol = PROTOCOL_NT1, ++ },{ ++ .name = "NT1 - SIGNING_REQUIRED", ++ .signing_setting = SMB_SIGNING_REQUIRED, ++ .protocol = PROTOCOL_NT1, ++ }, ++ }; ++ ++ printf("starting large_readx test\n"); ++ ++ if (!torture_open_connection(&cli1, 0)) { ++ goto out; ++ } ++ ++ normal_caps = smb1cli_conn_capabilities(cli1->conn); ++ ++ if (!(normal_caps & CAP_LARGE_READX)) { ++ d_printf("Server doesn't have CAP_LARGE_READX 0x%x\n", ++ (unsigned int)normal_caps); ++ goto out; ++ } ++ ++ /* Create a file of size 4MB. */ ++ status = cli_ntcreate(cli1, fname, 0, GENERIC_ALL_ACCESS, ++ FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, ++ 0, 0, &fnum1); ++ ++ if (!NT_STATUS_IS_OK(status)) { ++ d_printf("open %s failed: %s\n", fname, nt_errstr(status)); ++ goto out; ++ } ++ ++ /* Write file_size bytes. */ ++ buf = talloc_zero_array(frame, uint8_t, file_size); ++ if (buf == NULL) { ++ goto out; ++ } ++ ++ status = cli_writeall(cli1, ++ fnum1, ++ 0, ++ buf, ++ 0, ++ file_size, ++ NULL); ++ if (!NT_STATUS_IS_OK(status)) { ++ d_printf("cli_writeall failed: %s\n", nt_errstr(status)); ++ goto out; ++ } ++ ++ status = cli_close(cli1, fnum1); ++ if (!NT_STATUS_IS_OK(status)) { ++ d_printf("cli_close failed: %s\n", nt_errstr(status)); ++ goto out; ++ } ++ ++ fnum1 = UINT16_MAX; ++ ++ for (i=0; i < ARRAY_SIZE(runs); i++) { ++ enum smb_signing_setting saved_signing_setting = signing_state; ++ uint16_t fnum2 = -1; ++ ++ if (do_encrypt && ++ (runs[i].signing_setting == SMB_SIGNING_REQUIRED)) ++ { ++ d_printf("skip[%u] - %s\n", (unsigned)i, runs[i].name); ++ continue; ++ } ++ ++ d_printf("run[%u] - %s\n", (unsigned)i, runs[i].name); ++ ++ signing_state = runs[i].signing_setting; ++ cli2 = open_nbt_connection(); ++ signing_state = saved_signing_setting; ++ if (cli2 == NULL) { ++ goto out; ++ } ++ ++ status = smbXcli_negprot(cli2->conn, ++ cli2->timeout, ++ runs[i].protocol, ++ runs[i].protocol); ++ if (!NT_STATUS_IS_OK(status)) { ++ goto out; ++ } ++ ++ status = cli_session_setup(cli2, ++ username, ++ password, ++ strlen(password)+1, ++ password, ++ strlen(password)+1, ++ workgroup); ++ if (!NT_STATUS_IS_OK(status)) { ++ goto out; ++ } ++ ++ status = cli_tree_connect(cli2, ++ share, ++ "?????", ++ password, ++ strlen(password)+1); ++ if (!NT_STATUS_IS_OK(status)) { ++ goto out; ++ } ++ ++ cli_set_timeout(cli2, 120000); /* set a really long timeout (2 minutes) */ ++ ++ normal_caps = smb1cli_conn_capabilities(cli2->conn); ++ ++ if (!(normal_caps & CAP_LARGE_READX)) { ++ d_printf("Server doesn't have CAP_LARGE_READX 0x%x\n", ++ (unsigned int)normal_caps); ++ goto out; ++ } ++ ++ if (do_encrypt) { ++ if (force_cli_encryption(cli2, share) == false) { ++ goto out; ++ } ++ } else if (SERVER_HAS_UNIX_CIFS(cli2)) { ++ uint16_t major, minor; ++ uint32_t caplow, caphigh; ++ ++ status = cli_unix_extensions_version(cli2, ++ &major, &minor, ++ &caplow, &caphigh); ++ if (!NT_STATUS_IS_OK(status)) { ++ goto out; ++ } ++ } ++ ++ status = cli_ntcreate(cli2, fname, 0, FILE_READ_DATA, ++ FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, ++ 0, 0, &fnum2); ++ if (!NT_STATUS_IS_OK(status)) { ++ d_printf("Second open %s failed: %s\n", fname, nt_errstr(status)); ++ goto out; ++ } ++ ++ /* All reads must return less than file_size bytes. */ ++ if (!large_readx_tests(cli2, fnum2, buf)) { ++ goto out; ++ } ++ ++ status = cli_close(cli2, fnum2); ++ if (!NT_STATUS_IS_OK(status)) { ++ d_printf("cli_close failed: %s\n", nt_errstr(status)); ++ goto out; ++ } ++ fnum2 = -1; ++ ++ if (!torture_close_connection(cli2)) { ++ goto out; ++ } ++ cli2 = NULL; ++ } ++ ++ correct = true; ++ printf("Success on large_readx test\n"); ++ ++ out: ++ ++ if (cli2) { ++ if (!torture_close_connection(cli2)) { ++ correct = false; ++ } ++ } ++ ++ if (cli1) { ++ if (fnum1 != UINT16_MAX) { ++ status = cli_close(cli1, fnum1); ++ if (!NT_STATUS_IS_OK(status)) { ++ d_printf("cli_close failed: %s\n", nt_errstr(status)); ++ } ++ fnum1 = UINT16_MAX; ++ } ++ ++ status = cli_unlink(cli1, fname, ++ FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); ++ if (!NT_STATUS_IS_OK(status)) { ++ printf("unlink failed (%s)\n", nt_errstr(status)); ++ } ++ ++ if (!torture_close_connection(cli1)) { ++ correct = false; ++ } ++ } ++ ++ TALLOC_FREE(frame); ++ ++ printf("finished large_readx test\n"); ++ return correct; ++} ++ + static bool run_cli_echo(int dummy) + { + struct cli_state *cli; +@@ -9151,6 +9486,7 @@ static struct { + { "CHAIN2", run_chain2, 0}, + { "CHAIN3", run_chain3, 0}, + { "WINDOWS-WRITE", run_windows_write, 0}, ++ { "LARGE_READX", run_large_readx, 0}, + { "NTTRANS-CREATE", run_nttrans_create, 0}, + { "NTTRANS-FSCTL", run_nttrans_fsctl, 0}, + { "CLI_ECHO", run_cli_echo, 0}, +-- +1.8.1.3 + + +From a583f665617302e4e554e01014eb34aeaaece16c Mon Sep 17 00:00:00 2001 +From: Jeremy Allison +Date: Wed, 13 Mar 2013 15:45:12 -0700 +Subject: [PATCH 14/16] s3:selftest: Add LARGE_READX test into our make test + infrastructure. + +Tested against non-encrypted and encrypted connections. + +Signed-off-by: Jeremy Allison +Reviewed-by: Stefan Metzmacher +--- + source3/selftest/tests.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/source3/selftest/tests.py b/source3/selftest/tests.py +index 57c80f2..4453c4d 100755 +--- a/source3/selftest/tests.py ++++ b/source3/selftest/tests.py +@@ -54,7 +54,7 @@ plantestsuite("samba3.blackbox.registry.upgrade", "s3dc:local", [os.path.join(sa + tests = ["FDPASS", "LOCK1", "LOCK2", "LOCK3", "LOCK4", "LOCK5", "LOCK6", "LOCK7", "LOCK9", + "UNLINK", "BROWSE", "ATTR", "TRANS2", "TORTURE", + "OPLOCK1", "OPLOCK2", "OPLOCK4", "STREAMERROR", +- "DIR", "DIR1", "DIR-CREATETIME", "TCON", "TCONDEV", "RW1", "RW2", "RW3", "RW-SIGNING", ++ "DIR", "DIR1", "DIR-CREATETIME", "TCON", "TCONDEV", "RW1", "RW2", "RW3", "LARGE_READX", "RW-SIGNING", + "OPEN", "XCOPY", "RENAME", "DELETE", "DELETE-LN", "PROPERTIES", "W2K", + "TCON2", "IOCTL", "CHKPATH", "FDSESS", "CHAIN1", "CHAIN2", + "CHAIN3", +-- +1.8.1.3 + + +From 6aabf00e5d4dbab653bc60164d855e2f8452541f Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Tue, 19 Mar 2013 17:11:03 +0100 +Subject: [PATCH 15/16] s4:torture: raw.read fix large reads against windows + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Jeremy Allison +--- + source4/torture/raw/read.c | 12 +++--------- + 1 file changed, 3 insertions(+), 9 deletions(-) + +diff --git a/source4/torture/raw/read.c b/source4/torture/raw/read.c +index 6586177..5a5ffee 100644 +--- a/source4/torture/raw/read.c ++++ b/source4/torture/raw/read.c +@@ -529,7 +529,7 @@ static bool test_readx(struct torture_context *tctx, struct smbcli_state *cli) + printf("SAMBA: large read extension\n"); + CHECK_VALUE(io.readx.out.nread, 80000); + } else { +- CHECK_VALUE(io.readx.out.nread, 0); ++ CHECK_VALUE(io.readx.out.nread, 0x10000); + } + CHECK_BUFFER(buf, seed, io.readx.out.nread); + +@@ -569,13 +569,7 @@ static bool test_readx(struct torture_context *tctx, struct smbcli_state *cli) + io.readx.in.maxcnt = 0x10000; + status = smb_raw_read(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); +- if (torture_setting_bool(tctx, "samba3", false) || +- torture_setting_bool(tctx, "samba4", false)) { +- printf("SAMBA: large read extension\n"); +- CHECK_VALUE(io.readx.out.nread, 0x10000); +- } else { +- CHECK_VALUE(io.readx.out.nread, 0); +- } ++ CHECK_VALUE(io.readx.out.nread, 0x10000); + + io.readx.in.maxcnt = 0x10001; + status = smb_raw_read(cli->tree, &io); +@@ -585,7 +579,7 @@ static bool test_readx(struct torture_context *tctx, struct smbcli_state *cli) + printf("SAMBA: large read extension\n"); + CHECK_VALUE(io.readx.out.nread, 0x10001); + } else { +- CHECK_VALUE(io.readx.out.nread, 0); ++ CHECK_VALUE(io.readx.out.nread, 0x10000); + } + } else { + printf("Server does not support the CAP_LARGE_READX extension\n"); +-- +1.8.1.3 + + +From d51a804664e5525c12d979da7788a4aa21e42af3 Mon Sep 17 00:00:00 2001 +From: Stefan Metzmacher +Date: Wed, 20 Mar 2013 08:49:20 +0100 +Subject: [PATCH 16/16] s4:torture: let raw.read accept larger reads than + 0x10000 + +Signed-off-by: Stefan Metzmacher +Reviewed-by: Jeremy Allison +--- + source4/torture/raw/read.c | 6 ++---- + 1 file changed, 2 insertions(+), 4 deletions(-) + +diff --git a/source4/torture/raw/read.c b/source4/torture/raw/read.c +index 5a5ffee..59089bf 100644 +--- a/source4/torture/raw/read.c ++++ b/source4/torture/raw/read.c +@@ -524,8 +524,7 @@ static bool test_readx(struct torture_context *tctx, struct smbcli_state *cli) + CHECK_STATUS(status, NT_STATUS_OK); + CHECK_VALUE(io.readx.out.remaining, 0xFFFF); + CHECK_VALUE(io.readx.out.compaction_mode, 0); +- if (torture_setting_bool(tctx, "samba3", false) || +- torture_setting_bool(tctx, "samba4", false)) { ++ if (io.readx.out.nread == io.readx.in.maxcnt) { + printf("SAMBA: large read extension\n"); + CHECK_VALUE(io.readx.out.nread, 80000); + } else { +@@ -574,8 +573,7 @@ static bool test_readx(struct torture_context *tctx, struct smbcli_state *cli) + io.readx.in.maxcnt = 0x10001; + status = smb_raw_read(cli->tree, &io); + CHECK_STATUS(status, NT_STATUS_OK); +- if (torture_setting_bool(tctx, "samba3", false) || +- torture_setting_bool(tctx, "samba4", false)) { ++ if (io.readx.out.nread == io.readx.in.maxcnt) { + printf("SAMBA: large read extension\n"); + CHECK_VALUE(io.readx.out.nread, 0x10001); + } else { +-- +1.8.1.3 + diff --git a/samba.spec b/samba.spec index 75d4235..85fcf65 100644 --- a/samba.spec +++ b/samba.spec @@ -1,7 +1,7 @@ # Set --with testsuite or %bcond_without to run the Samba torture testsuite. %bcond_with testsuite -%define main_release 2 +%define main_release 3 %define samba_version 4.0.4 %define talloc_version 2.0.7 @@ -79,6 +79,7 @@ Source201: README.downgrade Patch0: samba-4.0.3-fix_pidl_with_gcc48.patch Patch1: samba-4.0.3-fix_pdb_ldapsam.patch Patch2: samba-4.0.3-fix_libcmdline-credentials_linking.patch +Patch3: samba-4.0.4-fix_large_read_handling.patch BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) @@ -437,6 +438,7 @@ the local kerberos library to use the same KDC as samba and winbind use %patch0 -p1 -b .pidl_gcc48 %patch1 -p1 -b .pdb_ldapsam %patch2 -p1 -b .libreplace_linking +%patch3 -p1 -b .large_read %build %global _talloc_lib ,talloc,pytalloc,pytalloc-util @@ -516,8 +518,6 @@ the local kerberos library to use the same KDC as samba and winbind use --without-pam_smbpass %endif -export WAFCACHE=/tmp/wafcache -mkdir -p $WAFCACHE make %{?_smp_mflags} # Build PIDL for installation into vendor directories before @@ -1357,6 +1357,10 @@ rm -rf %{buildroot} %{_mandir}/man7/winbind_krb5_locator.7* %changelog +* Fri Mar 22 2013 - Andreas Schneider - 2:4.0.4-3 +- resolves: #919405 - Fix and improve large_readx handling for broken clients. +- resolves: #924525 - Don't use waf caching. + * Wed Mar 20 2013 - Andreas Schneider - 2:4.0.4-2 - resolves: #923765 - Improve packaging of README files.