From 9d9f7afab61d83071580066d80e27f9aa3952bec Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 13 Mar 2013 14:56:06 -0700 Subject: [PATCH 01/12] Ensure we send CAP_LARGE_READX/CAP_LARGE_WRITEX to the server on SMB1 sessionsetupX. A Windows client doesn't do this, but that's because they never do large reads/writes over SMB1. It's in the spec that this should occur, and Samba 3.6.x uses it. Also, MacOSX, CIFSFS and Android (jCIFS) honour this setting and send it. We need to as well in order to give servers a better idea of our capabilities. Signed-off-by: Jeremy Allison --- libcli/smb/smb_constants.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libcli/smb/smb_constants.h b/libcli/smb/smb_constants.h index f1ecbe9..c447795 100644 --- a/libcli/smb/smb_constants.h +++ b/libcli/smb/smb_constants.h @@ -234,6 +234,8 @@ enum smb_signing_setting { CAP_NT_SMBS | \ CAP_STATUS32 | \ CAP_LEVEL_II_OPLOCKS | \ + CAP_LARGE_READX | \ + CAP_LARGE_WRITEX | \ CAP_EXTENDED_SECURITY | \ 0) #define SMB_CAP_SERVER_MASK ( \ @@ -245,8 +247,6 @@ enum smb_signing_setting { CAP_NT_FIND | \ CAP_DFS | \ CAP_W2K_SMBS | \ - CAP_LARGE_READX | \ - CAP_LARGE_WRITEX | \ CAP_LWIO | \ CAP_UNIX | \ 0) -- 1.8.1.3 From 835064fb252feca20e18c78d44fa5bf455df918d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 18 Mar 2013 15:02:55 +0100 Subject: [PATCH 02/12] 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 4c60a05..cd995e9 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 b1b4667c6d5b866affd467ce464aefc64a8c0a7d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 13 Mar 2013 15:23:52 -0700 Subject: [PATCH 03/12] 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 cd995e9..5a5828a 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 a2156d366a580d7d8af3de98c83695a2b235cc12 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 18 Mar 2013 09:33:00 +0100 Subject: [PATCH 04/12] 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 75c1683..47e7f1b 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 c3b950fb2bab660e04790a6fc536c0fd53d76abd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 18 Mar 2013 10:10:25 +0100 Subject: [PATCH 05/12] 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 ec7a405629d7e5322df650756bde982c4e44615f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 18 Mar 2013 12:36:30 +0100 Subject: [PATCH 06/12] 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 1640cca..fcb970d 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 bd22dd3..7e13049 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -801,7 +801,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 1111acfcb98909b0ff71374debcf3b71ddc477b4 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 15 Mar 2013 11:53:04 -0700 Subject: [PATCH 07/12] 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 2c31f15..edcfb77 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 9022be0b7422e8691c106a8d5d41f9f06238cffe Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 15 Mar 2013 11:57:48 -0700 Subject: [PATCH 08/12] 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 --- source3/smbd/reply.c | 99 +++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 74 insertions(+), 25 deletions(-) diff --git a/source3/smbd/reply.c b/source3/smbd/reply.c index edcfb77..842a86d 100644 --- a/source3/smbd/reply.c +++ b/source3/smbd/reply.c @@ -3848,6 +3848,72 @@ 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_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; + } + + 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 +3959,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 f94f8b92c0929b635d8b344ecce1a7861ddd9953 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Mon, 18 Mar 2013 19:50:38 +0100 Subject: [PATCH 09/12] s4:smb_server: fix large read_andx requests Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- source4/smb_server/smb/reply.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/source4/smb_server/smb/reply.c b/source4/smb_server/smb/reply.c index bae6b2c..0f1c7ce 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; /* parse request */ if (req->in.wct != 12) { @@ -869,13 +870,16 @@ 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; - } + 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 0x1000 + */ + 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 e0e38dc1353ed33743ca5c6e06d3491baf1359f7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 18 Mar 2013 15:05:24 -0700 Subject: [PATCH 10/12] 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 --- source3/smbd/process.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/source3/smbd/process.c b/source3/smbd/process.c index fcb970d..b5577cb 100644 --- a/source3/smbd/process.c +++ b/source3/smbd/process.c @@ -1271,10 +1271,13 @@ static bool create_outbuf(TALLOC_CTX *mem_ctx, struct smb_request *req, uint32_t num_bytes) { /* - * Protect against integer wrap + * Protect against integer wrap. + * 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. */ if ((num_bytes > 0xffffff) - || ((num_bytes + smb_size + num_words*2) > 0xffffff)) { + || ((num_bytes + smb_size - 4 + num_words*2) > 0xffffff)) { char *msg; if (asprintf(&msg, "num_bytes too large: %u", (unsigned)num_bytes) == -1) { @@ -1283,6 +1286,11 @@ static bool create_outbuf(TALLOC_CTX *mem_ctx, struct smb_request *req, smb_panic(msg); } + /* + * We don't subtract the 4 from smb_size here as we + * are explicitly allocating space for the entire + * type+length (4 bytes) + SMB_HEADER (2 bytes) + bcc bytes. + */ *outbuf = talloc_array(mem_ctx, char, smb_size + num_words*2 + num_bytes); if (*outbuf == NULL) { -- 1.8.1.3 From fbca97530287ca40352fef263e055ea4a7dd2969 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 13 Mar 2013 15:43:21 -0700 Subject: [PATCH 11/12] Add new LARGE_READX test to investigate large SMBreadX behavior. Signed-off-by: Jeremy Allison --- source3/torture/torture.c | 314 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 314 insertions(+) diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 93b9cfd..0aa3a23 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -7239,6 +7239,319 @@ 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 - (smb_size -4 + 12*2)); +} + +static bool check_read_call(struct cli_state *cli, + uint16_t fnum, + uint8_t *buf, + size_t len_requested) +{ + NTSTATUS status; + struct tevent_req *req = NULL; + ssize_t len_read = 0; + size_t len_expected = 0; + struct tevent_context *ev = NULL; + + ev = samba_tevent_context_init(talloc_tos()); + if (ev == NULL) { + return false; + } + + req = cli_read_andx_send(talloc_tos(), + ev, + cli, + fnum, + 0, + len_requested); + + if (!tevent_req_poll_ntstatus(req, ev, &status)) { + return false; + } + + status = cli_read_andx_recv(req, &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(req); + 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 10000 bytes. */ + if (check_read_call(cli, fnum, buf, 0x10000) == false) { + return false; + } + /* A read of 0x1FFFF - (smb_size -4 + 12*2) should return + the requested number of bytes. */ + if (check_read_call(cli, fnum, buf, 0x1FFFF - (smb_size -4 + 12*2)) == 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 *cli = NULL; + bool correct = false; + const char *fname = "\\large_readx.dat"; + NTSTATUS status; + uint16_t fnum = -1; + uint32_t normal_caps = 0; + size_t file_size = 20*1024*1024; + TALLOC_CTX *frame = talloc_stackframe(); + + printf("starting large_readx test\n"); + + if (!torture_open_connection(&cli, 0)) { + goto out; + } + + normal_caps = smb1cli_conn_capabilities(cli->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 do_encrypt is true, we already + * set up UNIX extensions. + */ + if (SERVER_HAS_UNIX_CIFS(cli)) { + status = torture_setup_unix_extensions(cli); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + } + } + + cli_unlink(cli, fname, FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + + /* Create a file of size 4MB. */ + status = cli_ntcreate(cli, fname, 0, GENERIC_ALL_ACCESS, + FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, + 0, 0, &fnum); + + 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(cli, + fnum, + 0, + buf, + 0, + file_size, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + d_printf("cli_writeall failed: %s\n", nt_errstr(status)); + goto out; + } + + /* All reads must return less than file_size bytes. */ + if (!large_readx_tests(cli, fnum, buf)) { + goto out; + } + + status = cli_close(cli, fnum); + if (!NT_STATUS_IS_OK(status)) { + d_printf("cli_close failed: %s\n", nt_errstr(status)); + goto out; + } + + fnum = -1; + + if (!torture_close_connection(cli)) { + goto out; + } + + cli = NULL; + + /* + * Open a second connection ensuring we don't + * announce ourselves as Samba. This way we + * should elicit the same behavior from a + * Samba server as we give to a Windows + * or MacOSX client. + */ + + if (!(cli = open_nbt_connection())) { + goto out; + } + + /* Ensure we don't announce ourselves as Samba. */ + status = smbXcli_negprot(cli->conn, + cli->timeout, + PROTOCOL_NT1, + PROTOCOL_NT1); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + status = cli_session_setup(cli, + username, + password, + strlen(password)+1, + password, + strlen(password)+1, + workgroup); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + status = cli_tree_connect(cli, + share, + "?????", + password, + strlen(password)+1); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + + cli_set_timeout(cli, 120000); /* set a really long timeout (2 minutes) */ + + normal_caps = smb1cli_conn_capabilities(cli->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(cli, share) == false) { + goto out; + } + } else if (SERVER_HAS_UNIX_CIFS(cli)) { + status = torture_setup_unix_extensions(cli); + if (!NT_STATUS_IS_OK(status)) { + goto out; + } + } + + status = cli_ntcreate(cli, fname, 0, FILE_READ_DATA, + FILE_ATTRIBUTE_NORMAL, 0, FILE_OPEN, + 0, 0, &fnum); + + 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(cli, fnum, buf)) { + goto out; + } + + correct = true; + printf("Success on large_readx test\n"); + + out: + + if (fnum != -1) { + status = cli_close(cli, fnum); + if (!NT_STATUS_IS_OK(status)) { + d_printf("cli_close failed: %s\n", nt_errstr(status)); + } + fnum = -1; + } + + status = cli_unlink(cli, + fname, + FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_HIDDEN); + if (!NT_STATUS_IS_OK(status)) { + printf("unlink failed (%s)\n", nt_errstr(status)); + } + + if (cli) { + if (!torture_close_connection(cli)) { + correct = false; + } + } + + TALLOC_FREE(frame); + + printf("finished large_readx test\n"); + return correct; +} + + static bool run_cli_echo(int dummy) { struct cli_state *cli; @@ -9153,6 +9466,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 feac318e6f742553323f5b40637901db447add97 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 13 Mar 2013 15:45:12 -0700 Subject: [PATCH 12/12] 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 30253ca..1c123f5 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