From 22588dec1a451c7ce847a4b8d735bdc20c592771 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 15:17:01 -0700 Subject: [PATCH 01/70] s3:param: Correctly set up cli_maxprotocol, cli_minprotocol in our parameter block. Set to PROTOCOL_NT1, PROTOCOL_CORE by default. Bug: https://bugzilla.samba.org/show_bug.cgi?id=9829 Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit f2fb829cee81996c62ff91cb8d1e9997008ffb42) --- source3/include/proto.h | 2 ++ source3/param/loadparm.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/source3/include/proto.h b/source3/include/proto.h index a9270fc..e3d2006 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1190,6 +1190,8 @@ int lp_deadtime(void); bool lp_getwd_cache(void); int lp_srv_maxprotocol(void); int lp_srv_minprotocol(void); +int lp_cli_maxprotocol(void); +int lp_cli_minprotocol(void); int lp_security(void); int lp__server_role(void); int lp__security(void); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index fa2f9b6..229ebd8 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -828,6 +828,8 @@ static void init_globals(bool reinit_globals) Globals.open_files_db_hash_size = SMB_OPEN_DATABASE_TDB_HASH_SIZE; Globals.srv_maxprotocol = PROTOCOL_SMB3_00; Globals.srv_minprotocol = PROTOCOL_LANMAN1; + Globals.cli_maxprotocol = PROTOCOL_NT1; + Globals.cli_minprotocol = PROTOCOL_CORE; Globals.security = SEC_USER; Globals.bEncryptPasswords = true; Globals.clientSchannel = Auto; -- 1.8.3 From 03cd018603d8c699ff9b772653932606da2002f7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:08:49 +0200 Subject: [PATCH 02/70] s3:client: avoid interpret_protocol() lp_set_cmdline("client max protocol",...) and lp_cli_maxprotocol() are the more generic solution. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 861ee9319f3cce8f104fd30c7139323ac3d3319d) --- source3/client/client.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source3/client/client.c b/source3/client/client.c index d03d1a4..d09d012 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -58,7 +58,7 @@ const char *cmd_ptr = NULL; static int io_bufsize = 524288; static int name_type = 0x20; -static int max_protocol = PROTOCOL_NT1; +static int max_protocol = -1; static int process_tok(char *tok); static int cmd_help(void); @@ -5456,7 +5456,7 @@ static int do_message_op(struct user_auth_info *a_info) } break; case 'm': - max_protocol = interpret_protocol(poptGetOptArg(pc), max_protocol); + lp_set_cmdline("client max protocol", poptGetOptArg(pc)); break; case 'T': /* We must use old option processing for this. Find the @@ -5574,6 +5574,8 @@ static int do_message_op(struct user_auth_info *a_info) /* Ensure we have a password (or equivalent). */ set_cmdline_auth_info_getpass(auth_info); + max_protocol = lp_cli_maxprotocol(); + if (tar_type) { if (cmdstr) process_command_string(cmdstr); -- 1.8.3 From 3f48951312457eaad25e1caf2a6d0c393e208d83 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:10:13 +0200 Subject: [PATCH 03/70] s3:torture: avoid interpret_protocol() lp_set_cmdline("client max protocol",...) and lp_cli_maxprotocol() are the more generic solution. https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 2c3c8caa0cc7b085231b2edc100ce2332e1e0085) --- source3/torture/masktest.c | 5 +++-- source3/torture/torture.c | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source3/torture/masktest.c b/source3/torture/masktest.c index 8332e80..bca35aa 100644 --- a/source3/torture/masktest.c +++ b/source3/torture/masktest.c @@ -27,7 +27,7 @@ static fstring password; static fstring username; static int got_pass; -static int max_protocol = PROTOCOL_NT1; +static int max_protocol = -1; static bool showall = False; static bool old_list = False; static const char *maskchars = "<>\"?*abc."; @@ -510,7 +510,7 @@ static void usage(void) verbose++; break; case 'M': - max_protocol = interpret_protocol(optarg, max_protocol); + lp_set_cmdline("client max protocol", optarg); break; case 'U': fstrcpy(username,optarg); @@ -548,6 +548,7 @@ static void usage(void) argc -= optind; argv += optind; + max_protocol = lp_cli_maxprotocol(); cli = connect_one(share); if (!cli) { diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 3c6db30..c6c5322 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -46,7 +46,6 @@ extern char *optarg; extern int optind; fstring host, workgroup, share, password, username, myname; -static int max_protocol = PROTOCOL_NT1; static const char *sockops="TCP_NODELAY"; int torture_nprocs=1; static int port_to_use=0; @@ -9713,7 +9712,7 @@ static void usage(void) fstrcpy(workgroup,optarg); break; case 'm': - max_protocol = interpret_protocol(optarg, max_protocol); + lp_set_cmdline("client max protocol", optarg); break; case 'N': torture_nprocs = atoi(optarg); -- 1.8.3 From e9fd87a0f36700fcb21a4404832fc4eb09dde565 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:11:41 +0200 Subject: [PATCH 04/70] s3:lib: remove unused interpret_protocol() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 9188ee4ab195a18b1bd697bced8613f98a6a91d9) --- source3/include/proto.h | 1 - source3/lib/util.c | 25 ------------------------- 2 files changed, 26 deletions(-) diff --git a/source3/include/proto.h b/source3/include/proto.h index e3d2006..493d1da 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -401,7 +401,6 @@ void add_to_large_array(TALLOC_CTX *mem_ctx, size_t element_size, ssize_t *array_size); char *get_myname(TALLOC_CTX *ctx); char *get_mydnsdomname(TALLOC_CTX *ctx); -int interpret_protocol(const char *str,int def); char *automount_lookup(TALLOC_CTX *ctx, const char *user_name); char *automount_lookup(TALLOC_CTX *ctx, const char *user_name); bool process_exists(const struct server_id pid); diff --git a/source3/lib/util.c b/source3/lib/util.c index 93aab3c..bf6c8c5 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -559,31 +559,6 @@ char *get_mydnsdomname(TALLOC_CTX *ctx) } } -/**************************************************************************** - Interpret a protocol description string, with a default. -****************************************************************************/ - -int interpret_protocol(const char *str,int def) -{ - if (strequal(str,"NT1")) - return(PROTOCOL_NT1); - if (strequal(str,"LANMAN2")) - return(PROTOCOL_LANMAN2); - if (strequal(str,"LANMAN1")) - return(PROTOCOL_LANMAN1); - if (strequal(str,"CORE")) - return(PROTOCOL_CORE); - if (strequal(str,"COREPLUS")) - return(PROTOCOL_COREPLUS); - if (strequal(str,"CORE+")) - return(PROTOCOL_COREPLUS); - - DEBUG(0,("Unrecognised protocol level %s\n",str)); - - return(def); -} - - #if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT)) /****************************************************************** Remove any mount options such as -rsize=2048,wsize=2048 etc. -- 1.8.3 From 22213fcc85f2c43bd2e2c3f352e675bca68e6ed9 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 11:35:44 -0700 Subject: [PATCH 05/70] s3:libsmb: Modify cli_start_connection_connected() to use lp_cli_minprotocol()/lp_cli_maxprotocol() instead of hard coding PROTOCOL_CORE, PROTOCOL_NT1. https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 42f510c155b98f3df5106aebd1de54d1749b9b1c) --- source3/libsmb/cliconnect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 7179c4f..fa9d99f 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -3123,7 +3123,8 @@ static void cli_start_connection_connected(struct tevent_req *subreq) subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn, state->cli->timeout, - PROTOCOL_CORE, PROTOCOL_NT1); + lp_cli_minprotocol(), + lp_cli_maxprotocol()); if (tevent_req_nomem(subreq, req)) { return; } -- 1.8.3 From eb34cbcc3a70d055356e67ced5b9ec90360f52c6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 9 Aug 2013 11:15:48 -0700 Subject: [PATCH 06/70] s3:libsmb: Ensure we ask for DEFAULT_SMB2_MAX_CREDITS on successful negprot. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 14421323d1dd3744cb8553f0e6a5a7436554bf2d) --- source3/libsmb/cliconnect.c | 10 ++++++++++ source3/libsmb/clidfs.c | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index fa9d99f..d74ea0e 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -3135,6 +3135,8 @@ static void cli_start_connection_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); + struct cli_start_connection_state *state = tevent_req_data( + req, struct cli_start_connection_state); NTSTATUS status; status = smbXcli_negprot_recv(subreq); @@ -3142,6 +3144,13 @@ static void cli_start_connection_done(struct tevent_req *subreq) if (tevent_req_nterror(req, status)) { return; } + + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + /* Ensure we ask for some initial credits. */ + smb2cli_conn_set_max_credits(state->cli->conn, + DEFAULT_SMB2_MAX_CREDITS); + } + tevent_req_done(req); } @@ -3156,6 +3165,7 @@ static NTSTATUS cli_start_connection_recv(struct tevent_req *req, return status; } *output_cli = state->cli; + return NT_STATUS_OK; } diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c index 95f8817..1ed6ac5 100644 --- a/source3/libsmb/clidfs.c +++ b/source3/libsmb/clidfs.c @@ -160,6 +160,11 @@ static NTSTATUS do_connect(TALLOC_CTX *ctx, return status; } + if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) { + /* Ensure we ask for some initial credits. */ + smb2cli_conn_set_max_credits(c->conn, DEFAULT_SMB2_MAX_CREDITS); + } + username = get_cmdline_auth_info_username(auth_info); password = get_cmdline_auth_info_password(auth_info); -- 1.8.3 From 59414d8deb68eefff7fbeff77694e69f2238f9c0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:46:34 +0200 Subject: [PATCH 07/70] s3:lib/netapi: make use of lp_cli_maxprotocol() https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 7e455e9ed2b298df6b735a89abdd75564375ef34) --- source3/lib/netapi/cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/lib/netapi/cm.c b/source3/lib/netapi/cm.c index 36e8731..da3d2e1 100644 --- a/source3/lib/netapi/cm.c +++ b/source3/lib/netapi/cm.c @@ -111,7 +111,7 @@ static WERROR libnetapi_open_ipc_connection(struct libnetapi_ctx *ctx, server_name, "IPC$", auth_info, false, false, - PROTOCOL_NT1, + lp_cli_maxprotocol(), 0, 0x20, &cli_ipc); if (NT_STATUS_IS_OK(status)) { cli_set_username(cli_ipc, ctx->username); -- 1.8.3 From c1ad9b85bc0caa8bd31e16e6e14a9b6da268a780 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:48:31 +0200 Subject: [PATCH 08/70] s3:winbindd: make use of lp_cli_{min,max}protocol() This changes winbindd back to use NT1 as defeault. https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit dd9155a7ec7f1989cb18e79907d0fa1c9ee845a4) --- source3/winbindd/winbindd_cm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 185aa4f..4c1a8cc 100644 --- a/source3/winbindd/winbindd_cm.c +++ b/source3/winbindd/winbindd_cm.c @@ -841,8 +841,9 @@ static NTSTATUS cm_prepare_connection(const struct winbindd_domain *domain, cli_set_timeout(*cli, 10000); /* 10 seconds */ - result = smbXcli_negprot((*cli)->conn, (*cli)->timeout, PROTOCOL_CORE, - PROTOCOL_LATEST); + result = smbXcli_negprot((*cli)->conn, (*cli)->timeout, + lp_cli_minprotocol(), + lp_cli_maxprotocol()); if (!NT_STATUS_IS_OK(result)) { DEBUG(1, ("cli_negprot failed: %s\n", nt_errstr(result))); -- 1.8.3 From 193ae27d16870a2f0c3ddd17052b3ac2e57f07c2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 14:00:45 +0200 Subject: [PATCH 09/70] s3:libsmb: use lp_cli_minprotocol() in do_connect() https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 42a493dff0e4ade04b6e94caf0b7ae14b6cf60eb) --- source3/libsmb/clidfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c index 1ed6ac5..1d92843 100644 --- a/source3/libsmb/clidfs.c +++ b/source3/libsmb/clidfs.c @@ -150,7 +150,8 @@ static NTSTATUS do_connect(TALLOC_CTX *ctx, } DEBUG(4,(" session request ok\n")); - status = smbXcli_negprot(c->conn, c->timeout, PROTOCOL_CORE, + status = smbXcli_negprot(c->conn, c->timeout, + lp_cli_minprotocol(), max_protocol); if (!NT_STATUS_IS_OK(status)) { -- 1.8.3 From 8ca5c458fa58cbcbf4264113cb75ee031022fadc Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 14:01:36 +0200 Subject: [PATCH 10/70] s3:libsmb: make use of lp_cli_{min,max}protocol() in SMBC_server_internal() https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit daeb0bdfc49ace6151bbca34cbbf55486d66abb6) --- source3/libsmb/libsmb_server.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c index fc3977e..7a20c30 100644 --- a/source3/libsmb/libsmb_server.c +++ b/source3/libsmb/libsmb_server.c @@ -449,9 +449,9 @@ SMBC_server_internal(TALLOC_CTX *ctx, cli_set_timeout(c, smbc_getTimeout(context)); - status = smbXcli_negprot(c->conn, c->timeout, PROTOCOL_CORE, - PROTOCOL_NT1); - + status = smbXcli_negprot(c->conn, c->timeout, + lp_cli_minprotocol(), + lp_cli_maxprotocol()); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; -- 1.8.3 From bd55bb2a5114c2215c60d3bae4d8474b596a1031 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 11:43:16 -0700 Subject: [PATCH 11/70] s3:smbcacls: Add -m option to smbcacls. https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Jeremy Allison Signed-off-by: Stefan Metzmacher Reviewed-by: Stefan Metzmacher (cherry picked from commit f6ce50a8aca9eb024af4eb5e3dd620fe5e04e913) --- source3/utils/smbcacls.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c index 39400c8..3ee7034 100644 --- a/source3/utils/smbcacls.c +++ b/source3/utils/smbcacls.c @@ -1386,6 +1386,7 @@ static struct cli_state *connect_one(struct user_auth_info *auth_info, }, { "test-args", 't', POPT_ARG_NONE, &test_args, 1, "Test arguments"}, { "domain-sid", 0, POPT_ARG_STRING, &domain_sid, 0, "Domain SID for sddl", "SID"}, + { "max-protocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set the max protocol level", "LEVEL" }, POPT_COMMON_SAMBA POPT_COMMON_CONNECTION POPT_COMMON_CREDENTIALS @@ -1456,6 +1457,9 @@ static struct cli_state *connect_one(struct user_auth_info *auth_info, owner_username = poptGetOptArg(pc); change_mode = REQUEST_INHERIT; break; + case 'm': + lp_set_cmdline("client max protocol", poptGetOptArg(pc)); + break; } } -- 1.8.3 From 83ce973660bffeb1cbb2a057e8ea8847479252c1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 08:12:08 +0200 Subject: [PATCH 12/70] libcli/smb: fix the credit handling on a SMB1 => SMB2 negotiate Our cur_credit value had 1 credit too many in the case of an SMB1 => SMB2 upgrade. When we max out the credits the server disconnected the connection. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 97288b7f1048c1bf712463293a1e62737738292c) --- libcli/smb/smbXcli_base.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 5a5828a..b950900 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -4404,9 +4404,14 @@ static NTSTATUS smbXcli_negprot_dispatch_incoming(struct smbXcli_conn *conn, /* * we got an SMB2 answer, which consumed sequence number 0 - * so we need to use 1 as the next one + * so we need to use 1 as the next one. + * + * we also need to set the current credits to 0 + * as we consumed the initial one. The SMB2 answer + * hopefully grant us a new credit. */ conn->smb2.mid = 1; + conn->smb2.cur_credits = 0; tevent_req_set_callback(subreq, smbXcli_negprot_smb2_done, req); conn->dispatch_incoming = smb2cli_conn_dispatch_incoming; return smb2cli_conn_dispatch_incoming(conn, tmp_mem, inbuf); -- 1.8.3 From 950e20584dac56417707110c05397fa29e935f4b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 14:41:24 -0700 Subject: [PATCH 13/70] libcli/smb: Fix smb2cli_write_recv() and smb2cli_write() to return the bytes written. Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 00f784ec91d2cfa95b20327ac20f5bc3fa1f400e) --- libcli/smb/smb2cli_write.c | 30 +++++++++++++++++++++++++----- libcli/smb/smbXcli_base.h | 6 ++++-- source3/libsmb/cli_np_tstream.c | 7 +++++-- source3/torture/test_smb2.c | 14 +++++++------- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/libcli/smb/smb2cli_write.c b/libcli/smb/smb2cli_write.c index 8e65460..89137bd 100644 --- a/libcli/smb/smb2cli_write.c +++ b/libcli/smb/smb2cli_write.c @@ -26,6 +26,7 @@ struct smb2cli_write_state { uint8_t fixed[48]; uint8_t dyn_pad[1]; + uint32_t written; }; static void smb2cli_write_done(struct tevent_req *subreq); @@ -94,7 +95,11 @@ static void smb2cli_write_done(struct tevent_req *subreq) struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); + struct smb2cli_write_state *state = + tevent_req_data(req, + struct smb2cli_write_state); NTSTATUS status; + struct iovec *iov; static const struct smb2cli_req_expected_response expected[] = { { .status = NT_STATUS_OK, @@ -102,18 +107,32 @@ static void smb2cli_write_done(struct tevent_req *subreq) } }; - status = smb2cli_req_recv(subreq, NULL, NULL, + status = smb2cli_req_recv(subreq, state, &iov, expected, ARRAY_SIZE(expected)); TALLOC_FREE(subreq); if (tevent_req_nterror(req, status)) { return; } + state->written = IVAL(iov[1].iov_base, 4); tevent_req_done(req); } -NTSTATUS smb2cli_write_recv(struct tevent_req *req) +NTSTATUS smb2cli_write_recv(struct tevent_req *req, uint32_t *written) { - return tevent_req_simple_recv_ntstatus(req); + struct smb2cli_write_state *state = + tevent_req_data(req, + struct smb2cli_write_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + if (written) { + *written = state->written; + } + tevent_req_received(req); + return NT_STATUS_OK; } NTSTATUS smb2cli_write(struct smbXcli_conn *conn, @@ -126,7 +145,8 @@ NTSTATUS smb2cli_write(struct smbXcli_conn *conn, uint64_t fid_volatile, uint32_t remaining_bytes, uint32_t flags, - const uint8_t *data) + const uint8_t *data, + uint32_t *written) { TALLOC_CTX *frame = talloc_stackframe(); struct tevent_context *ev; @@ -155,7 +175,7 @@ NTSTATUS smb2cli_write(struct smbXcli_conn *conn, if (!tevent_req_poll_ntstatus(req, ev, &status)) { goto fail; } - status = smb2cli_write_recv(req); + status = smb2cli_write_recv(req, written); fail: TALLOC_FREE(frame); return status; diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index f7b60d3..997869b 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -429,7 +429,8 @@ struct tevent_req *smb2cli_write_send(TALLOC_CTX *mem_ctx, uint32_t remaining_bytes, uint32_t flags, const uint8_t *data); -NTSTATUS smb2cli_write_recv(struct tevent_req *req); +NTSTATUS smb2cli_write_recv(struct tevent_req *req, + uint32_t *written); NTSTATUS smb2cli_write(struct smbXcli_conn *conn, uint32_t timeout_msec, struct smbXcli_session *session, @@ -440,7 +441,8 @@ NTSTATUS smb2cli_write(struct smbXcli_conn *conn, uint64_t fid_volatile, uint32_t remaining_bytes, uint32_t flags, - const uint8_t *data); + const uint8_t *data, + uint32_t *written); struct tevent_req *smb2cli_flush_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, diff --git a/source3/libsmb/cli_np_tstream.c b/source3/libsmb/cli_np_tstream.c index c7ec664..07835a5 100644 --- a/source3/libsmb/cli_np_tstream.c +++ b/source3/libsmb/cli_np_tstream.c @@ -527,8 +527,11 @@ static void tstream_cli_np_writev_write_done(struct tevent_req *subreq) if (cli_nps->is_smb1) { status = cli_write_andx_recv(subreq, &written); } else { - status = smb2cli_write_recv(subreq); - written = cli_nps->write.ofs; // TODO: get the value from the server + uint32_t smb2_written; + status = smb2cli_write_recv(subreq, &smb2_written); + if (NT_STATUS_IS_OK(status)) { + written = smb2_written; + } } TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { diff --git a/source3/torture/test_smb2.c b/source3/torture/test_smb2.c index ec695da..7ca9f49 100644 --- a/source3/torture/test_smb2.c +++ b/source3/torture/test_smb2.c @@ -91,7 +91,7 @@ bool run_smb2_basic(int dummy) status = smb2cli_write(cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_write returned %s\n", nt_errstr(status)); return false; @@ -349,7 +349,7 @@ bool run_smb2_session_reconnect(int dummy) status = smb2cli_write(cli1->conn, cli1->timeout, cli1->smb2.session, cli1->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_write returned %s\n", nt_errstr(status)); return false; @@ -545,7 +545,7 @@ bool run_smb2_session_reconnect(int dummy) status = smb2cli_write(cli2->conn, cli2->timeout, cli2->smb2.session, cli2->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) && !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) { @@ -605,7 +605,7 @@ bool run_smb2_session_reconnect(int dummy) status = smb2cli_write(cli2->conn, cli2->timeout, cli2->smb2.session, cli1->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) && !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) { @@ -670,7 +670,7 @@ bool run_smb2_session_reconnect(int dummy) status = smb2cli_write(cli2->conn, cli2->timeout, cli2->smb2.session, cli2->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_write returned %s\n", nt_errstr(status)); return false; @@ -765,7 +765,7 @@ bool run_smb2_tcon_dependence(int dummy) status = smb2cli_write(cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_write returned %s\n", nt_errstr(status)); return false; @@ -1172,7 +1172,7 @@ bool run_smb2_multi_channel(int dummy) status = smb2cli_write(cli1->conn, cli1->timeout, cli1->smb2.session, cli1->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_write returned %s\n", nt_errstr(status)); return false; -- 1.8.3 From 2704b5d553a12efa6bf395fe8a937a5971339902 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 15:01:50 -0700 Subject: [PATCH 14/70] libcli/smb: Change smb2cli_create() and smb2cli_create_recv() to return a parameter blob of the newly opened/created file. Will use in the smb2 client code. Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 1229881df6bd22d4b5055ad283061332ba1c9bc8) --- libcli/smb/smb2_create_blob.h | 12 +++++++++++ libcli/smb/smb2cli_create.c | 39 ++++++++++++++++----------------- libcli/smb/smbXcli_base.h | 7 ++++-- source3/libsmb/cli_np_tstream.c | 3 ++- source3/torture/test_smb2.c | 48 +++++++++++++++++++++++++++-------------- 5 files changed, 69 insertions(+), 40 deletions(-) diff --git a/libcli/smb/smb2_create_blob.h b/libcli/smb/smb2_create_blob.h index 008befe..2f915b3 100644 --- a/libcli/smb/smb2_create_blob.h +++ b/libcli/smb/smb2_create_blob.h @@ -33,6 +33,18 @@ struct smb2_create_blobs { struct smb2_create_blob *blobs; }; +struct smb2_create_returns { + uint8_t oplock_level; + uint32_t create_action; + NTTIME creation_time; + NTTIME last_access_time; + NTTIME last_write_time; + NTTIME change_time; + uint64_t allocation_size; + uint64_t end_of_file; + uint32_t file_attributes; +}; + /* parse a set of SMB2 create blobs */ diff --git a/libcli/smb/smb2cli_create.c b/libcli/smb/smb2cli_create.c index 627bdcb..020a468 100644 --- a/libcli/smb/smb2cli_create.c +++ b/libcli/smb/smb2cli_create.c @@ -27,17 +27,9 @@ struct smb2cli_create_state { uint8_t fixed[56]; - uint8_t oplock_level; - uint32_t create_action; - NTTIME creation_time; - NTTIME last_access_time; - NTTIME last_write_time; - NTTIME change_time; - uint64_t allocation_size; - uint64_t end_of_file; - uint32_t file_attributes; uint64_t fid_persistent; uint64_t fid_volatile; + struct smb2_create_returns cr; struct smb2_create_blobs blobs; }; @@ -179,15 +171,15 @@ static void smb2cli_create_done(struct tevent_req *subreq) body = (uint8_t *)iov[1].iov_base; - state->oplock_level = CVAL(body, 2); - state->create_action = IVAL(body, 4); - state->creation_time = BVAL(body, 8); - state->last_access_time = BVAL(body, 16); - state->last_write_time = BVAL(body, 24); - state->change_time = BVAL(body, 32); - state->allocation_size = BVAL(body, 40); - state->end_of_file = BVAL(body, 48); - state->file_attributes = IVAL(body, 56); + state->cr.oplock_level = CVAL(body, 2); + state->cr.create_action = IVAL(body, 4); + state->cr.creation_time = BVAL(body, 8); + state->cr.last_access_time = BVAL(body, 16); + state->cr.last_write_time = BVAL(body, 24); + state->cr.change_time = BVAL(body, 32); + state->cr.allocation_size = BVAL(body, 40); + state->cr.end_of_file = BVAL(body, 48); + state->cr.file_attributes = IVAL(body, 56); state->fid_persistent = BVAL(body, 64); state->fid_volatile = BVAL(body, 72); @@ -213,7 +205,8 @@ static void smb2cli_create_done(struct tevent_req *subreq) NTSTATUS smb2cli_create_recv(struct tevent_req *req, uint64_t *fid_persistent, - uint64_t *fid_volatile) + uint64_t *fid_volatile, + struct smb2_create_returns *cr) { struct smb2cli_create_state *state = tevent_req_data(req, @@ -225,6 +218,9 @@ NTSTATUS smb2cli_create_recv(struct tevent_req *req, } *fid_persistent = state->fid_persistent; *fid_volatile = state->fid_volatile; + if (cr) { + *cr = state->cr; + } return NT_STATUS_OK; } @@ -242,7 +238,8 @@ NTSTATUS smb2cli_create(struct smbXcli_conn *conn, uint32_t create_options, struct smb2_create_blobs *blobs, uint64_t *fid_persistent, - uint64_t *fid_volatile) + uint64_t *fid_volatile, + struct smb2_create_returns *cr) { TALLOC_CTX *frame = talloc_stackframe(); struct tevent_context *ev; @@ -273,7 +270,7 @@ NTSTATUS smb2cli_create(struct smbXcli_conn *conn, if (!tevent_req_poll_ntstatus(req, ev, &status)) { goto fail; } - status = smb2cli_create_recv(req, fid_persistent, fid_volatile); + status = smb2cli_create_recv(req, fid_persistent, fid_volatile, cr); fail: TALLOC_FREE(frame); return status; diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index 997869b..a497e13 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -28,6 +28,7 @@ struct smb_trans_enc_state; struct GUID; struct iovec; struct smb2_create_blobs; +struct smb2_create_returns; struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx, int fd, @@ -353,7 +354,8 @@ struct tevent_req *smb2cli_create_send( struct smb2_create_blobs *blobs); NTSTATUS smb2cli_create_recv(struct tevent_req *req, uint64_t *fid_persistent, - uint64_t *fid_volatile); + uint64_t *fid_volatile, + struct smb2_create_returns *cr); NTSTATUS smb2cli_create(struct smbXcli_conn *conn, uint32_t timeout_msec, struct smbXcli_session *session, @@ -368,7 +370,8 @@ NTSTATUS smb2cli_create(struct smbXcli_conn *conn, uint32_t create_options, struct smb2_create_blobs *blobs, uint64_t *fid_persistent, - uint64_t *fid_volatile); + uint64_t *fid_volatile, + struct smb2_create_returns *cr); struct tevent_req *smb2cli_close_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, diff --git a/source3/libsmb/cli_np_tstream.c b/source3/libsmb/cli_np_tstream.c index 07835a5..f3a9962 100644 --- a/source3/libsmb/cli_np_tstream.c +++ b/source3/libsmb/cli_np_tstream.c @@ -208,7 +208,8 @@ static void tstream_cli_np_open_done(struct tevent_req *subreq) } else { status = smb2cli_create_recv(subreq, &state->fid_persistent, - &state->fid_volatile); + &state->fid_volatile, + NULL); } TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { diff --git a/source3/torture/test_smb2.c b/source3/torture/test_smb2.c index 7ca9f49..3bcd2ed 100644 --- a/source3/torture/test_smb2.c +++ b/source3/torture/test_smb2.c @@ -83,7 +83,8 @@ bool run_smb2_basic(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create returned %s\n", nt_errstr(status)); return false; @@ -145,7 +146,8 @@ bool run_smb2_basic(int dummy) FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create returned %s\n", nt_errstr(status)); return false; @@ -341,7 +343,8 @@ bool run_smb2_session_reconnect(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create on cli1 %s\n", nt_errstr(status)); return false; @@ -575,7 +578,8 @@ bool run_smb2_session_reconnect(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) && !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) { printf("smb2cli_create on cli2 %s\n", nt_errstr(status)); @@ -635,7 +639,8 @@ bool run_smb2_session_reconnect(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED) && !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) { @@ -662,7 +667,8 @@ bool run_smb2_session_reconnect(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create on cli2 %s\n", nt_errstr(status)); return false; @@ -757,7 +763,8 @@ bool run_smb2_tcon_dependence(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create on cli %s\n", nt_errstr(status)); return false; @@ -1164,7 +1171,8 @@ bool run_smb2_multi_channel(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create on cli2 %s\n", nt_errstr(status)); return false; @@ -1324,7 +1332,8 @@ bool run_smb2_multi_channel(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { printf("smb2cli_create %s\n", nt_errstr(status)); return false; @@ -1341,7 +1350,8 @@ bool run_smb2_multi_channel(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { printf("smb2cli_create %s\n", nt_errstr(status)); return false; @@ -1358,7 +1368,8 @@ bool run_smb2_multi_channel(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { printf("smb2cli_create %s\n", nt_errstr(status)); return false; @@ -1489,7 +1500,8 @@ bool run_smb2_session_reauth(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create %s\n", nt_errstr(status)); return false; @@ -1508,7 +1520,8 @@ bool run_smb2_session_reauth(int dummy) FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &dir_persistent, - &dir_volatile); + &dir_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create returned %s\n", nt_errstr(status)); return false; @@ -1691,7 +1704,8 @@ bool run_smb2_session_reauth(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { printf("smb2cli_create %s\n", nt_errstr(status)); return false; @@ -1710,7 +1724,8 @@ bool run_smb2_session_reauth(int dummy) FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &dir_persistent, - &dir_volatile); + &dir_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { printf("smb2cli_create returned %s\n", nt_errstr(status)); return false; @@ -1865,7 +1880,8 @@ bool run_smb2_session_reauth(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create %s\n", nt_errstr(status)); return false; -- 1.8.3 From 10fe80ecc448d45fa3151df43b2811fd19a26c40 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 09:50:29 +0200 Subject: [PATCH 15/70] libcli/smb: calculate the credit charge on the input and output dyn_len Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 318735fd5e15c5fd7010c0f657c86d27b45279ac) --- libcli/smb/smbXcli_base.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index b950900..ef9d82a 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -246,6 +246,11 @@ struct smbXcli_req_state { */ struct iovec *recv_iov; + /* + * the expected max for the response dyn_len + */ + uint32_t max_dyn_len; + uint16_t credit_charge; bool should_sign; @@ -2787,7 +2792,12 @@ NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs, } if (state->conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) { - charge = (MAX(state->smb2.dyn_len, 1) - 1)/ 65536 + 1; + uint32_t max_dyn_len = 1; + + max_dyn_len = MAX(max_dyn_len, state->smb2.dyn_len); + max_dyn_len = MAX(max_dyn_len, state->smb2.max_dyn_len); + + charge = (max_dyn_len - 1)/ 65536 + 1; } else { charge = 1; } -- 1.8.3 From 59c706c417ec70f7e9e5352c200f649bdfb58a54 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 09:54:42 +0200 Subject: [PATCH 16/70] libcli/smb: pass max_dyn_len to smb2cli_req_create() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 4a3352020db962ef40728d8a754da8a9418ca8a7) --- libcli/smb/smbXcli_base.c | 11 ++++++++--- libcli/smb/smbXcli_base.h | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index ef9d82a..60c1c9f 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -2494,7 +2494,7 @@ static bool smb2cli_req_cancel(struct tevent_req *req) 0, /* timeout */ tcon, session, fixed, fixed_len, - NULL, 0); + NULL, 0, 0); if (subreq == NULL) { return false; } @@ -2543,7 +2543,8 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx, const uint8_t *fixed, uint16_t fixed_len, const uint8_t *dyn, - uint32_t dyn_len) + uint32_t dyn_len, + uint32_t max_dyn_len) { struct tevent_req *req; struct smbXcli_req_state *state; @@ -2616,6 +2617,7 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx, state->smb2.fixed_len = fixed_len; state->smb2.dyn = dyn; state->smb2.dyn_len = dyn_len; + state->smb2.max_dyn_len = max_dyn_len; if (state->smb2.should_encrypt) { SIVAL(state->smb2.transform, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC); @@ -2985,12 +2987,15 @@ struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx, { struct tevent_req *req; NTSTATUS status; + uint32_t max_dyn_len = 0; req = smb2cli_req_create(mem_ctx, ev, conn, cmd, additional_flags, clear_flags, timeout_msec, tcon, session, - fixed, fixed_len, dyn, dyn_len); + fixed, fixed_len, + dyn, dyn_len, + max_dyn_len); if (req == NULL) { return NULL; } diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index a497e13..017c0f0 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -218,7 +218,8 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx, const uint8_t *fixed, uint16_t fixed_len, const uint8_t *dyn, - uint32_t dyn_len); + uint32_t dyn_len, + uint32_t max_dyn_len); void smb2cli_req_set_notify_async(struct tevent_req *req); NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs, int num_reqs); -- 1.8.3 From c900045a6b3150cbaf054b2f0824e5f59f2429ca Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 10:25:52 +0200 Subject: [PATCH 17/70] libcli/smb: pass max_dyn_len to smb2cli_req_send() This way we can calculate the correct credit charge for requests with large output buffers. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 44b53937d59842a63e2cbfa92219f4f519530b0a) --- libcli/smb/smb2cli_close.c | 3 ++- libcli/smb/smb2cli_create.c | 13 ++++++++++++- libcli/smb/smb2cli_echo.c | 3 ++- libcli/smb/smb2cli_flush.c | 3 ++- libcli/smb/smb2cli_ioctl.c | 13 ++++++++++++- libcli/smb/smb2cli_query_directory.c | 3 ++- libcli/smb/smb2cli_query_info.c | 3 ++- libcli/smb/smb2cli_read.c | 3 ++- libcli/smb/smb2cli_session.c | 6 ++++-- libcli/smb/smb2cli_set_info.c | 3 ++- libcli/smb/smb2cli_write.c | 3 ++- libcli/smb/smbXcli_base.c | 7 ++++--- libcli/smb/smbXcli_base.h | 3 ++- source3/libsmb/smb2cli_tcon.c | 6 ++++-- source4/libcli/smb2/transport.c | 9 ++++++--- 15 files changed, 60 insertions(+), 21 deletions(-) diff --git a/libcli/smb/smb2cli_close.c b/libcli/smb/smb2cli_close.c index ed15a20..5e31056 100644 --- a/libcli/smb/smb2cli_close.c +++ b/libcli/smb/smb2cli_close.c @@ -60,7 +60,8 @@ struct tevent_req *smb2cli_close_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - NULL, 0); + NULL, 0, /* dyn* */ + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_create.c b/libcli/smb/smb2cli_create.c index 020a468..3f8d672 100644 --- a/libcli/smb/smb2cli_create.c +++ b/libcli/smb/smb2cli_create.c @@ -62,6 +62,7 @@ struct tevent_req *smb2cli_create_send( size_t blobs_offset; uint8_t *dyn; size_t dyn_len; + size_t max_dyn_len; req = tevent_req_create(mem_ctx, &state, struct smb2cli_create_state); @@ -129,13 +130,23 @@ struct tevent_req *smb2cli_create_send( data_blob_free(&blob); } + /* + * We use max_dyn_len = 0 + * as we don't explicitly ask for any output length. + * + * But it's still possible for the server to return + * large create blobs. + */ + max_dyn_len = 0; + subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_CREATE, 0, 0, /* flags */ timeout_msec, tcon, session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + max_dyn_len); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_echo.c b/libcli/smb/smb2cli_echo.c index 29cbf26..39c592c 100644 --- a/libcli/smb/smb2cli_echo.c +++ b/libcli/smb/smb2cli_echo.c @@ -53,7 +53,8 @@ struct tevent_req *smb2cli_echo_send(TALLOC_CTX *mem_ctx, NULL, /* tcon */ NULL, /* session */ state->fixed, sizeof(state->fixed), - NULL, 0); + NULL, 0, /* dyn* */ + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_flush.c b/libcli/smb/smb2cli_flush.c index 0ca2699..f014720 100644 --- a/libcli/smb/smb2cli_flush.c +++ b/libcli/smb/smb2cli_flush.c @@ -58,7 +58,8 @@ struct tevent_req *smb2cli_flush_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - NULL, 0); + NULL, 0, /* dyn* */ + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_ioctl.c b/libcli/smb/smb2cli_ioctl.c index 15a990c..8de7635 100644 --- a/libcli/smb/smb2cli_ioctl.c +++ b/libcli/smb/smb2cli_ioctl.c @@ -61,6 +61,8 @@ struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx, uint32_t output_buffer_offset = 0; uint32_t output_buffer_length = 0; uint32_t pad_length = 0; + uint64_t tmp64; + uint32_t max_dyn_len = 0; req = tevent_req_create(mem_ctx, &state, struct smb2cli_ioctl_state); @@ -70,6 +72,14 @@ struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx, state->max_input_length = in_max_input_length; state->max_output_length = in_max_output_length; + tmp64 = in_max_input_length; + tmp64 += in_max_output_length; + if (tmp64 > UINT32_MAX) { + max_dyn_len = UINT32_MAX; + } else { + max_dyn_len = tmp64; + } + if (in_input_buffer) { input_buffer_offset = SMB2_HDR_BODY+0x38; input_buffer_length = in_input_buffer->length; @@ -139,7 +149,8 @@ struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + max_dyn_len); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_query_directory.c b/libcli/smb/smb2cli_query_directory.c index 32f5bee..bccc529 100644 --- a/libcli/smb/smb2cli_query_directory.c +++ b/libcli/smb/smb2cli_query_directory.c @@ -93,7 +93,8 @@ struct tevent_req *smb2cli_query_directory_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + outbuf_len); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_query_info.c b/libcli/smb/smb2cli_query_info.c index 9ec16b5..454f25a 100644 --- a/libcli/smb/smb2cli_query_info.c +++ b/libcli/smb/smb2cli_query_info.c @@ -96,7 +96,8 @@ struct tevent_req *smb2cli_query_info_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + in_max_output_length); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_read.c b/libcli/smb/smb2cli_read.c index 0adb403..4a31622 100644 --- a/libcli/smb/smb2cli_read.c +++ b/libcli/smb/smb2cli_read.c @@ -72,7 +72,8 @@ struct tevent_req *smb2cli_read_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - state->dyn_pad, sizeof(state->dyn_pad)); + state->dyn_pad, sizeof(state->dyn_pad), + length); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_session.c b/libcli/smb/smb2cli_session.c index 537c171..4418a0d 100644 --- a/libcli/smb/smb2cli_session.c +++ b/libcli/smb/smb2cli_session.c @@ -102,7 +102,8 @@ struct tevent_req *smb2cli_session_setup_send(TALLOC_CTX *mem_ctx, NULL, /* tcon */ session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + UINT16_MAX); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } @@ -258,7 +259,8 @@ struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx, NULL, /* tcon */ session, state->fixed, sizeof(state->fixed), - NULL, 0); + NULL, 0, /* dyn* */ + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_set_info.c b/libcli/smb/smb2cli_set_info.c index d5c7e58..6871370 100644 --- a/libcli/smb/smb2cli_set_info.c +++ b/libcli/smb/smb2cli_set_info.c @@ -88,7 +88,8 @@ struct tevent_req *smb2cli_set_info_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_write.c b/libcli/smb/smb2cli_write.c index 89137bd..6d0a0aa 100644 --- a/libcli/smb/smb2cli_write.c +++ b/libcli/smb/smb2cli_write.c @@ -82,7 +82,8 @@ struct tevent_req *smb2cli_write_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 60c1c9f..f64852b 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -2983,11 +2983,11 @@ struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx, const uint8_t *fixed, uint16_t fixed_len, const uint8_t *dyn, - uint32_t dyn_len) + uint32_t dyn_len, + uint32_t max_dyn_len) { struct tevent_req *req; NTSTATUS status; - uint32_t max_dyn_len = 0; req = smb2cli_req_create(mem_ctx, ev, conn, cmd, additional_flags, clear_flags, @@ -4259,7 +4259,8 @@ static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_sta state->timeout_msec, NULL, NULL, /* tcon, session */ state->smb2.fixed, sizeof(state->smb2.fixed), - state->smb2.dyn, dialect_count*2); + state->smb2.dyn, dialect_count*2, + UINT16_MAX); /* max_dyn_len */ } static void smbXcli_negprot_smb2_done(struct tevent_req *subreq) diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index 017c0f0..4ce39c0 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -242,7 +242,8 @@ struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx, const uint8_t *fixed, uint16_t fixed_len, const uint8_t *dyn, - uint32_t dyn_len); + uint32_t dyn_len, + uint32_t max_dyn_len); NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct iovec **piov, const struct smb2cli_req_expected_response *expected, diff --git a/source3/libsmb/smb2cli_tcon.c b/source3/libsmb/smb2cli_tcon.c index ab97f8d..b3136fa 100644 --- a/source3/libsmb/smb2cli_tcon.c +++ b/source3/libsmb/smb2cli_tcon.c @@ -85,7 +85,8 @@ struct tevent_req *smb2cli_tcon_send(TALLOC_CTX *mem_ctx, NULL, /* tcon */ cli->smb2.session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } @@ -211,7 +212,8 @@ struct tevent_req *smb2cli_tdis_send(TALLOC_CTX *mem_ctx, cli->smb2.tcon, cli->smb2.session, state->fixed, sizeof(state->fixed), - NULL, 0); + NULL, 0, /* dyn* */ + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c index bdab523..2ad16a9 100644 --- a/source4/libcli/smb2/transport.c +++ b/source4/libcli/smb2/transport.c @@ -151,7 +151,8 @@ void smb2_transport_send(struct smb2_request *req) NULL, /* body */ 0, /* body_fixed */ NULL, /* dyn */ - 0); /* dyn_len */ + 0, /* dyn_len */ + 0); /* max_dyn_len */ if (subreq != NULL) { smbXcli_req_set_pending(subreq); tevent_req_set_callback(subreq, @@ -190,7 +191,8 @@ void smb2_transport_send(struct smb2_request *req) tcon, session, body.data, body.length, - dyn.data, dyn.length); + dyn.data, dyn.length, + 0); /* max_dyn_len */ if (req->subreq == NULL) { req->state = SMB2_REQUEST_ERROR; req->status = NT_STATUS_NO_MEMORY; @@ -347,7 +349,8 @@ static void smb2_transport_break_handler(struct tevent_req *subreq) NULL, /* body */ 0, /* body_fixed */ NULL, /* dyn */ - 0); /* dyn_len */ + 0, /* dyn_len */ + 0); /* max_dyn_len */ if (subreq != NULL) { smbXcli_req_set_pending(subreq); tevent_req_set_callback(subreq, -- 1.8.3 From 966acfed1b2fbdc4f7b48fbec87877019c0290b5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 14:05:05 +0200 Subject: [PATCH 18/70] libcli/smb: add smb1cli_conn_req_possible() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 111f529a2a5832b822445bb4f63b142d8ccb2cb7) --- libcli/smb/smbXcli_base.c | 17 +++++++++++++++++ libcli/smb/smbXcli_base.h | 1 + 2 files changed, 18 insertions(+) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index f64852b..028f152 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -595,6 +595,23 @@ uint32_t smb1cli_conn_max_xmit(struct smbXcli_conn *conn) return conn->smb1.max_xmit; } +bool smb1cli_conn_req_possible(struct smbXcli_conn *conn) +{ + size_t pending; + uint16_t possible = conn->smb1.server.max_mux; + + pending = tevent_queue_length(conn->outgoing); + if (pending >= possible) { + return false; + } + pending += talloc_array_length(conn->pending); + if (pending >= possible) { + return false; + } + + return true; +} + uint32_t smb1cli_conn_server_session_key(struct smbXcli_conn *conn) { return conn->smb1.server.session_key; diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index 4ce39c0..6b3156f 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -69,6 +69,7 @@ bool smbXcli_req_set_pending(struct tevent_req *req); uint32_t smb1cli_conn_capabilities(struct smbXcli_conn *conn); uint32_t smb1cli_conn_max_xmit(struct smbXcli_conn *conn); +bool smb1cli_conn_req_possible(struct smbXcli_conn *conn); uint32_t smb1cli_conn_server_session_key(struct smbXcli_conn *conn); const uint8_t *smb1cli_conn_server_challenge(struct smbXcli_conn *conn); uint16_t smb1cli_conn_server_security_mode(struct smbXcli_conn *conn); -- 1.8.3 From 7c81c9e2383c392321605b52f381c7c99b190dd3 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 15:49:19 +0200 Subject: [PATCH 19/70] libcli/smb: add smb2cli_conn_req_possible() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 7efdc323d1a1abdae70bcafefe07b3cffcdb2521) --- libcli/smb/smbXcli_base.c | 22 ++++++++++++++++++++++ libcli/smb/smbXcli_base.h | 1 + 2 files changed, 23 insertions(+) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 028f152..b502f4f 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -2452,6 +2452,28 @@ bool smbXcli_conn_has_async_calls(struct smbXcli_conn *conn) || (talloc_array_length(conn->pending) != 0)); } +bool smb2cli_conn_req_possible(struct smbXcli_conn *conn, uint32_t *max_dyn_len) +{ + uint16_t credits = 1; + + if (conn->smb2.cur_credits == 0) { + if (max_dyn_len != NULL) { + *max_dyn_len = 0; + } + return false; + } + + if (conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) { + credits = conn->smb2.cur_credits; + } + + if (max_dyn_len != NULL) { + *max_dyn_len = credits * 65536; + } + + return true; +} + uint32_t smb2cli_conn_server_capabilities(struct smbXcli_conn *conn) { return conn->smb2.server.capabilities; diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index 6b3156f..a7cfcc3 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -199,6 +199,7 @@ NTSTATUS smb1cli_echo_recv(struct tevent_req *req); NTSTATUS smb1cli_echo(struct smbXcli_conn *conn, uint32_t timeout_msec, uint16_t num_echos, DATA_BLOB data); +bool smb2cli_conn_req_possible(struct smbXcli_conn *conn, uint32_t *max_dyn_len); uint32_t smb2cli_conn_server_capabilities(struct smbXcli_conn *conn); uint16_t smb2cli_conn_server_security_mode(struct smbXcli_conn *conn); uint32_t smb2cli_conn_max_trans_size(struct smbXcli_conn *conn); -- 1.8.3 From fda22b4763e7935e1af3ef57b5bde407e2faa4f8 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 14:10:59 +0200 Subject: [PATCH 20/70] s3:libsmb: rewrite cli_push* to use smb1cli_conn_req_possible() This works out if it's possible to ship the next request dynamically instead of relying on fixed values. The default window size is 16 MByte. We limit the number of outstanding chunks/requests to 256. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit b846b3acd2b217a0d67c1e8fcb039e03498c4e47) --- source3/libsmb/clireadwrite.c | 288 +++++++++++++++++++++++++++--------------- 1 file changed, 187 insertions(+), 101 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 47e7f1b..550c52b 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -1092,13 +1092,7 @@ NTSTATUS cli_writeall(struct cli_state *cli, uint16_t fnum, uint16_t mode, return status; } -struct cli_push_write_state { - struct tevent_req *req;/* This is the main request! Not the subreq */ - uint32_t idx; - off_t ofs; - uint8_t *buf; - size_t size; -}; +struct cli_push_chunk; struct cli_push_state { struct tevent_context *ev; @@ -1106,7 +1100,6 @@ struct cli_push_state { uint16_t fnum; uint16_t mode; off_t start_offset; - size_t window_size; size_t (*source)(uint8_t *buf, size_t n, void *priv); void *priv; @@ -1118,62 +1111,32 @@ struct cli_push_state { /* * Outstanding requests + * + * The maximum is 256: + * - which would be a window of 256 MByte + * for SMB2 with multi-credit + * or smb1 unix extentions. */ - uint32_t pending; - uint16_t max_reqs; - uint32_t num_reqs; - struct cli_push_write_state **reqs; + uint16_t max_chunks; + uint16_t num_chunks; + uint16_t num_waiting; + struct cli_push_chunk *chunks; }; -static void cli_push_written(struct tevent_req *req); - -static bool cli_push_write_setup(struct tevent_req *req, - struct cli_push_state *state, - uint32_t idx) -{ - struct cli_push_write_state *substate; +struct cli_push_chunk { + struct cli_push_chunk *prev, *next; + struct tevent_req *req;/* This is the main request! Not the subreq */ struct tevent_req *subreq; + off_t ofs; + uint8_t *buf; + size_t total_size; + size_t tmp_size; + bool done; +}; - substate = talloc(state->reqs, struct cli_push_write_state); - if (!substate) { - return false; - } - substate->req = req; - substate->idx = idx; - substate->ofs = state->next_offset; - substate->buf = talloc_array(substate, uint8_t, state->chunk_size); - if (!substate->buf) { - talloc_free(substate); - return false; - } - substate->size = state->source(substate->buf, - state->chunk_size, - state->priv); - if (substate->size == 0) { - state->eof = true; - /* nothing to send */ - talloc_free(substate); - return true; - } - - subreq = cli_writeall_send(substate, - state->ev, state->cli, - state->fnum, state->mode, - substate->buf, - substate->ofs, - substate->size); - if (!subreq) { - talloc_free(substate); - return false; - } - tevent_req_set_callback(subreq, cli_push_written, substate); - - state->reqs[idx] = substate; - state->pending += 1; - state->next_offset += substate->size; - - return true; -} +static void cli_push_setup_chunks(struct tevent_req *req); +static void cli_push_chunk_ship(struct cli_push_chunk *chunk); +static void cli_push_chunk_done(struct tevent_req *subreq); struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, @@ -1185,8 +1148,8 @@ struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, { struct tevent_req *req; struct cli_push_state *state; - uint32_t i; size_t page_size = 1024; + uint64_t tmp64; req = tevent_req_create(mem_ctx, &state, struct cli_push_state); if (req == NULL) { @@ -1199,8 +1162,6 @@ struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, state->mode = mode; state->source = source; state->priv = priv; - state->eof = false; - state->pending = 0; state->next_offset = start_offset; state->chunk_size = cli_write_max_bufsize(cli, mode, 14); @@ -1208,77 +1169,202 @@ struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, state->chunk_size &= ~(page_size - 1); } - state->max_reqs = smbXcli_conn_max_requests(cli->conn); - if (window_size == 0) { - window_size = state->max_reqs * state->chunk_size; + /* + * We use 16 MByte as default window size. + */ + window_size = 16 * 1024 * 1024; } - state->num_reqs = window_size/state->chunk_size; + + tmp64 = window_size/state->chunk_size; if ((window_size % state->chunk_size) > 0) { - state->num_reqs += 1; + tmp64 += 1; } - state->num_reqs = MIN(state->num_reqs, state->max_reqs); - state->num_reqs = MAX(state->num_reqs, 1); + tmp64 = MAX(tmp64, 1); + tmp64 = MIN(tmp64, 256); + state->max_chunks = tmp64; - state->reqs = talloc_zero_array(state, struct cli_push_write_state *, - state->num_reqs); - if (state->reqs == NULL) { - goto failed; + /* + * We defer the callback because of the complex + * substate/subfunction logic + */ + tevent_req_defer_callback(req, ev); + + cli_push_setup_chunks(req); + if (!tevent_req_is_in_progress(req)) { + return tevent_req_post(req, ev); } - for (i=0; inum_reqs; i++) { - if (!cli_push_write_setup(req, state, i)) { - goto failed; + return req; +} + +static void cli_push_setup_chunks(struct tevent_req *req) +{ + struct cli_push_state *state = + tevent_req_data(req, + struct cli_push_state); + struct cli_push_chunk *chunk, *next = NULL; + size_t i; + + for (chunk = state->chunks; chunk; chunk = next) { + /* + * Note that chunk might be removed from this call. + */ + next = chunk->next; + cli_push_chunk_ship(chunk); + if (!tevent_req_is_in_progress(req)) { + return; + } + } + + for (i = state->num_chunks; i < state->max_chunks; i++) { + + if (state->num_waiting > 0) { + return; } if (state->eof) { break; } + + chunk = talloc_zero(state, struct cli_push_chunk); + if (tevent_req_nomem(chunk, req)) { + return; + } + chunk->req = req; + chunk->ofs = state->next_offset; + chunk->buf = talloc_array(chunk, + uint8_t, + state->chunk_size); + if (tevent_req_nomem(chunk->buf, req)) { + return; + } + chunk->total_size = state->source(chunk->buf, + state->chunk_size, + state->priv); + if (chunk->total_size == 0) { + /* nothing to send */ + talloc_free(chunk); + state->eof = true; + break; + } + state->next_offset += chunk->total_size; + + DLIST_ADD_END(state->chunks, chunk, NULL); + state->num_chunks++; + state->num_waiting++; + + cli_push_chunk_ship(chunk); + if (!tevent_req_is_in_progress(req)) { + return; + } } - if (state->pending == 0) { - tevent_req_done(req); - return tevent_req_post(req, ev); + if (!state->eof) { + return; } - return req; + if (state->num_chunks > 0) { + return; + } + + tevent_req_done(req); +} + +static void cli_push_chunk_ship(struct cli_push_chunk *chunk) +{ + struct tevent_req *req = chunk->req; + struct cli_push_state *state = + tevent_req_data(req, + struct cli_push_state); + bool ok; + const uint8_t *buf; + off_t ofs; + size_t size; + + if (chunk->done) { + DLIST_REMOVE(state->chunks, chunk); + SMB_ASSERT(state->num_chunks > 0); + state->num_chunks--; + TALLOC_FREE(chunk); + + return; + } + + if (chunk->subreq != NULL) { + return; + } + + SMB_ASSERT(state->num_waiting > 0); + + buf = chunk->buf + chunk->tmp_size; + ofs = chunk->ofs + chunk->tmp_size; + size = chunk->total_size - chunk->tmp_size; + + ok = smb1cli_conn_req_possible(state->cli->conn); + if (!ok) { + return; + } + + chunk->subreq = cli_write_andx_send(chunk, + state->ev, + state->cli, + state->fnum, + state->mode, + buf, + ofs, + size); + if (tevent_req_nomem(chunk->subreq, req)) { + return; + } + tevent_req_set_callback(chunk->subreq, + cli_push_chunk_done, + chunk); - failed: - tevent_req_nterror(req, NT_STATUS_NO_MEMORY); - return tevent_req_post(req, ev); + state->num_waiting--; + return; } -static void cli_push_written(struct tevent_req *subreq) +static void cli_push_chunk_done(struct tevent_req *subreq) { - struct cli_push_write_state *substate = tevent_req_callback_data( - subreq, struct cli_push_write_state); - struct tevent_req *req = substate->req; - struct cli_push_state *state = tevent_req_data( - req, struct cli_push_state); + struct cli_push_chunk *chunk = + tevent_req_callback_data(subreq, + struct cli_push_chunk); + struct tevent_req *req = chunk->req; + struct cli_push_state *state = + tevent_req_data(req, + struct cli_push_state); NTSTATUS status; - uint32_t idx = substate->idx; + size_t expected = chunk->total_size - chunk->tmp_size; + size_t written; - state->reqs[idx] = NULL; - state->pending -= 1; + chunk->subreq = NULL; - status = cli_writeall_recv(subreq, NULL); + status = cli_write_andx_recv(subreq, &written); TALLOC_FREE(subreq); - TALLOC_FREE(substate); if (tevent_req_nterror(req, status)) { return; } - if (!state->eof) { - if (!cli_push_write_setup(req, state, idx)) { - tevent_req_nterror(req, NT_STATUS_NO_MEMORY); - return; - } + if (written > expected) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; } - if (state->pending == 0) { - tevent_req_done(req); + if (written == 0) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } + + chunk->tmp_size += written; + + if (chunk->tmp_size == chunk->total_size) { + chunk->done = true; + } else { + state->num_waiting++; + } + + cli_push_setup_chunks(req); } NTSTATUS cli_push_recv(struct tevent_req *req) -- 1.8.3 From 41c2df2023e7268be3acebb4635c405a546eb4c5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 18:03:50 +0200 Subject: [PATCH 21/70] s3:libsmb: rewrite cli_pull* to use smb1cli_conn_req_possible() This works out if it's possible to ship the next request dynamically instead of relying on fixed values. The default window size is 16 MByte. We limit the number of outstanding chunks/requests to 256. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 8062aefbe3c2fcc73e3d19af6663c8736c570f7c) --- source3/libsmb/clireadwrite.c | 417 +++++++++++++++++++++++++----------------- 1 file changed, 246 insertions(+), 171 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 550c52b..dd5d4c2 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -388,23 +388,9 @@ static NTSTATUS cli_readall_recv(struct tevent_req *req, ssize_t *received, return NT_STATUS_OK; } -struct cli_pull_subreq { - struct tevent_req *req; - ssize_t received; - uint8_t *buf; -}; - -/* - * Parallel read support. - * - * cli_pull sends as many read&x requests as the server would allow via - * max_mux at a time. When replies flow back in, the data is written into - * the callback function "sink" in the right order. - */ +struct cli_pull_chunk; struct cli_pull_state { - struct tevent_req *req; - struct tevent_context *ev; struct cli_state *cli; uint16_t fnum; @@ -415,54 +401,49 @@ struct cli_pull_state { void *priv; size_t chunk_size; + off_t next_offset; + off_t remaining; /* - * Outstanding requests - */ - uint16_t max_reqs; - int num_reqs; - struct cli_pull_subreq *reqs; - - /* - * For how many bytes did we send requests already? - */ - off_t requested; - - /* - * Next request index to push into "sink". This walks around the "req" - * array, taking care that the requests are pushed to "sink" in the - * right order. If necessary (i.e. replies don't come in in the right - * order), replies are held back in "reqs". + * How many bytes did we push into "sink"? */ - int top_req; + off_t pushed; /* - * How many bytes did we push into "sink"? + * Outstanding requests + * + * The maximum is 256: + * - which would be a window of 256 MByte + * for SMB2 with multi-credit + * or smb1 unix extentions. */ - - off_t pushed; + uint16_t max_chunks; + uint16_t num_chunks; + uint16_t num_waiting; + struct cli_pull_chunk *chunks; }; -static char *cli_pull_print(struct tevent_req *req, TALLOC_CTX *mem_ctx) -{ - struct cli_pull_state *state = tevent_req_data( - req, struct cli_pull_state); - char *result; - - result = tevent_req_default_print(req, mem_ctx); - if (result == NULL) { - return NULL; - } - - return talloc_asprintf_append_buffer( - result, "num_reqs=%d, top_req=%d", - state->num_reqs, state->top_req); -} +struct cli_pull_chunk { + struct cli_pull_chunk *prev, *next; + struct tevent_req *req;/* This is the main request! Not the subreq */ + struct tevent_req *subreq; + off_t ofs; + uint8_t *buf; + size_t total_size; + size_t tmp_size; + bool done; +}; -static void cli_pull_read_done(struct tevent_req *read_req); +static void cli_pull_setup_chunks(struct tevent_req *req); +static void cli_pull_chunk_ship(struct cli_pull_chunk *chunk); +static void cli_pull_chunk_done(struct tevent_req *subreq); /* - * Prepare an async pull request + * Parallel read support. + * + * cli_pull sends as many read&x requests as the server would allow via + * max_mux at a time. When replies flow back in, the data is written into + * the callback function "sink" in the right order. */ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, @@ -476,16 +457,13 @@ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, { struct tevent_req *req; struct cli_pull_state *state; - int i; size_t page_size = 1024; + uint64_t tmp64; req = tevent_req_create(mem_ctx, &state, struct cli_pull_state); if (req == NULL) { return NULL; } - tevent_req_set_print_fn(req, cli_pull_print); - state->req = req; - state->cli = cli; state->ev = ev; state->fnum = fnum; @@ -493,9 +471,8 @@ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, state->size = size; state->sink = sink; state->priv = priv; - - state->pushed = 0; - state->top_req = 0; + state->next_offset = start_offset; + state->remaining = size; if (size == 0) { tevent_req_done(req); @@ -507,155 +484,251 @@ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, state->chunk_size &= ~(page_size - 1); } - state->max_reqs = smbXcli_conn_max_requests(cli->conn); + if (window_size == 0) { + /* + * We use 16 MByte as default window size. + */ + window_size = 16 * 1024 * 1024; + } + + tmp64 = window_size/state->chunk_size; + if ((window_size % state->chunk_size) > 0) { + tmp64 += 1; + } + tmp64 = MAX(tmp64, 1); + tmp64 = MIN(tmp64, 256); + state->max_chunks = tmp64; + + /* + * We defer the callback because of the complex + * substate/subfunction logic + */ + tevent_req_defer_callback(req, ev); + + cli_pull_setup_chunks(req); + if (!tevent_req_is_in_progress(req)) { + return tevent_req_post(req, ev); + } + + return req; +} - state->num_reqs = MAX(window_size/state->chunk_size, 1); - state->num_reqs = MIN(state->num_reqs, state->max_reqs); +static void cli_pull_setup_chunks(struct tevent_req *req) +{ + struct cli_pull_state *state = + tevent_req_data(req, + struct cli_pull_state); + struct cli_pull_chunk *chunk, *next = NULL; + size_t i; - state->reqs = talloc_zero_array(state, struct cli_pull_subreq, - state->num_reqs); - if (state->reqs == NULL) { - goto failed; + for (chunk = state->chunks; chunk; chunk = next) { + /* + * Note that chunk might be removed from this call. + */ + next = chunk->next; + cli_pull_chunk_ship(chunk); + if (!tevent_req_is_in_progress(req)) { + return; + } } - state->requested = 0; + for (i = state->num_chunks; i < state->max_chunks; i++) { - for (i=0; inum_reqs; i++) { - struct cli_pull_subreq *subreq = &state->reqs[i]; - off_t size_left; - size_t request_thistime; + if (state->num_waiting > 0) { + return; + } - if (state->requested >= size) { - state->num_reqs = i; + if (state->remaining == 0) { break; } - size_left = size - state->requested; - request_thistime = MIN(size_left, state->chunk_size); + chunk = talloc_zero(state, struct cli_pull_chunk); + if (tevent_req_nomem(chunk, req)) { + return; + } + chunk->req = req; + chunk->ofs = state->next_offset; + chunk->total_size = MIN(state->remaining, state->chunk_size); + state->next_offset += chunk->total_size; + state->remaining -= chunk->total_size; - subreq->req = cli_readall_send( - state->reqs, ev, cli, fnum, - state->start_offset + state->requested, - request_thistime); + DLIST_ADD_END(state->chunks, chunk, NULL); + state->num_chunks++; + state->num_waiting++; - if (subreq->req == NULL) { - goto failed; + cli_pull_chunk_ship(chunk); + if (!tevent_req_is_in_progress(req)) { + return; } - tevent_req_set_callback(subreq->req, cli_pull_read_done, req); - state->requested += request_thistime; } - return req; -failed: - TALLOC_FREE(req); - return NULL; -} + if (state->remaining > 0) { + return; + } -/* - * Handle incoming read replies, push the data into sink and send out new - * requests if necessary. - */ + if (state->num_chunks > 0) { + return; + } + + tevent_req_done(req); +} -static void cli_pull_read_done(struct tevent_req *subreq) +static void cli_pull_chunk_ship(struct cli_pull_chunk *chunk) { - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct cli_pull_state *state = tevent_req_data( - req, struct cli_pull_state); - struct cli_pull_subreq *pull_subreq = NULL; - NTSTATUS status; - int i; + struct tevent_req *req = chunk->req; + struct cli_pull_state *state = + tevent_req_data(req, + struct cli_pull_state); + bool ok; + off_t ofs; + size_t size; - for (i = 0; i < state->num_reqs; i++) { - pull_subreq = &state->reqs[i]; - if (subreq == pull_subreq->req) { - break; + if (chunk->done) { + NTSTATUS status; + + if (chunk != state->chunks) { + /* + * this chunk is not the + * first one in the list. + * + * which means we should not + * push it into the sink yet. + */ + return; + } + + if (chunk->tmp_size == 0) { + /* + * we git a short read, we're done + */ + tevent_req_done(req); + return; } + + status = state->sink((char *)chunk->buf, + chunk->tmp_size, + state->priv); + if (tevent_req_nterror(req, status)) { + return; + } + state->pushed += chunk->tmp_size; + + if (chunk->tmp_size < chunk->total_size) { + /* + * we git a short read, we're done + */ + tevent_req_done(req); + return; + } + + DLIST_REMOVE(state->chunks, chunk); + SMB_ASSERT(state->num_chunks > 0); + state->num_chunks--; + TALLOC_FREE(chunk); + + return; } - if (i == state->num_reqs) { - /* Huh -- received something we did not send?? */ - tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + + if (chunk->subreq != NULL) { return; } - status = cli_readall_recv(subreq, &pull_subreq->received, - &pull_subreq->buf); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(state->req, status); + SMB_ASSERT(state->num_waiting > 0); + + ofs = chunk->ofs + chunk->tmp_size; + size = chunk->total_size - chunk->tmp_size; + + ok = smb1cli_conn_req_possible(state->cli->conn); + if (!ok) { return; } - /* - * This loop is the one to take care of out-of-order replies. All - * pending requests are in state->reqs, state->reqs[top_req] is the - * one that is to be pushed next. If however a request later than - * top_req is replied to, then we can't push yet. If top_req is - * replied to at a later point then, we need to push all the finished - * requests. - */ + chunk->subreq = cli_read_andx_send(chunk, + state->ev, + state->cli, + state->fnum, + ofs, + size); + if (tevent_req_nomem(chunk->subreq, req)) { + return; + } + tevent_req_set_callback(chunk->subreq, + cli_pull_chunk_done, + chunk); - while (state->reqs[state->top_req].req != NULL) { - struct cli_pull_subreq *top_subreq; + state->num_waiting--; + return; +} - DEBUG(11, ("cli_pull_read_done: top_req = %d\n", - state->top_req)); +static void cli_pull_chunk_done(struct tevent_req *subreq) +{ + struct cli_pull_chunk *chunk = + tevent_req_callback_data(subreq, + struct cli_pull_chunk); + struct tevent_req *req = chunk->req; + struct cli_pull_state *state = + tevent_req_data(req, + struct cli_pull_state); + NTSTATUS status; + size_t expected = chunk->total_size - chunk->tmp_size; + ssize_t received; + uint8_t *buf = NULL; - top_subreq = &state->reqs[state->top_req]; + chunk->subreq = NULL; - if (tevent_req_is_in_progress(top_subreq->req)) { - DEBUG(11, ("cli_pull_read_done: top request not yet " - "done\n")); - return; - } + status = cli_read_andx_recv(subreq, &received, &buf); + if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) { + received = 0; + status = NT_STATUS_OK; + } + if (tevent_req_nterror(req, status)) { + return; + } + + if (received > expected) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } - DEBUG(10, ("cli_pull_read_done: Pushing %d bytes, %d already " - "pushed\n", (int)top_subreq->received, - (int)state->pushed)); + if (received == 0) { + /* + * We got EOF we're done + */ + chunk->done = true; + cli_pull_setup_chunks(req); + return; + } - status = state->sink((char *)top_subreq->buf, - top_subreq->received, state->priv); - if (tevent_req_nterror(state->req, status)) { + if (received == chunk->total_size) { + /* + * We got it in the first run. + * + * We don't call TALLOC_FREE(subreq) + * here and keep the returned buffer. + */ + chunk->buf = buf; + } else if (chunk->buf == NULL) { + chunk->buf = talloc_array(chunk, uint8_t, chunk->total_size); + if (tevent_req_nomem(chunk->buf, req)) { return; } - state->pushed += top_subreq->received; - - TALLOC_FREE(state->reqs[state->top_req].req); - - if (state->requested < state->size) { - struct tevent_req *new_req; - off_t size_left; - size_t request_thistime; - - size_left = state->size - state->requested; - request_thistime = MIN(size_left, state->chunk_size); - - DEBUG(10, ("cli_pull_read_done: Requesting %d bytes " - "at %d, position %d\n", - (int)request_thistime, - (int)(state->start_offset - + state->requested), - state->top_req)); - - new_req = cli_readall_send( - state->reqs, state->ev, state->cli, - state->fnum, - state->start_offset + state->requested, - request_thistime); - - if (tevent_req_nomem(new_req, state->req)) { - return; - } - tevent_req_set_callback(new_req, cli_pull_read_done, - req); - - state->reqs[state->top_req].req = new_req; - state->requested += request_thistime; - } + } - state->top_req = (state->top_req+1) % state->num_reqs; + if (received != chunk->total_size) { + uint8_t *p = chunk->buf + chunk->tmp_size; + memcpy(p, buf, received); + TALLOC_FREE(subreq); } - tevent_req_done(req); + chunk->tmp_size += received; + + if (chunk->tmp_size == chunk->total_size) { + chunk->done = true; + } else { + state->num_waiting++; + } + + cli_pull_setup_chunks(req); } NTSTATUS cli_pull_recv(struct tevent_req *req, off_t *received) @@ -665,9 +738,11 @@ NTSTATUS cli_pull_recv(struct tevent_req *req, off_t *received) NTSTATUS status; if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); return status; } *received = state->pushed; + tevent_req_received(req); return NT_STATUS_OK; } -- 1.8.3 From b1043375be01d0c1e2184d543ed23d5bebf675a4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 18:23:55 +0200 Subject: [PATCH 22/70] s3:libsmb: remove unused cli_readall* Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 9193a58375691bfca9e3cce1ff61b2b6dd65a982) --- source3/libsmb/clireadwrite.c | 119 ------------------------------------------ 1 file changed, 119 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index dd5d4c2..10dc79b 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -269,125 +269,6 @@ NTSTATUS cli_read_andx_recv(struct tevent_req *req, ssize_t *received, return NT_STATUS_OK; } -struct cli_readall_state { - struct tevent_context *ev; - struct cli_state *cli; - uint16_t fnum; - off_t start_offset; - size_t size; - size_t received; - uint8_t *buf; -}; - -static void cli_readall_done(struct tevent_req *subreq); - -static struct tevent_req *cli_readall_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct cli_state *cli, - uint16_t fnum, - off_t offset, size_t size) -{ - struct tevent_req *req, *subreq; - struct cli_readall_state *state; - - req = tevent_req_create(mem_ctx, &state, struct cli_readall_state); - if (req == NULL) { - return NULL; - } - state->ev = ev; - state->cli = cli; - state->fnum = fnum; - state->start_offset = offset; - state->size = size; - state->received = 0; - state->buf = NULL; - - subreq = cli_read_andx_send(state, ev, cli, fnum, offset, size); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, cli_readall_done, req); - return req; -} - -static void cli_readall_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct cli_readall_state *state = tevent_req_data( - req, struct cli_readall_state); - ssize_t received; - uint8_t *buf; - NTSTATUS status; - - status = cli_read_andx_recv(subreq, &received, &buf); - if (tevent_req_nterror(req, status)) { - return; - } - - if (received == 0) { - /* EOF */ - tevent_req_done(req); - return; - } - - if ((state->received == 0) && (received == state->size)) { - /* Ideal case: Got it all in one run */ - state->buf = buf; - state->received += received; - tevent_req_done(req); - return; - } - - /* - * We got a short read, issue a read for the - * rest. Unfortunately we have to allocate the buffer - * ourselves now, as our caller expects to receive a single - * buffer. cli_read_andx does it from the buffer received from - * the net, but with a short read we have to put it together - * from several reads. - */ - - if (state->buf == NULL) { - state->buf = talloc_array(state, uint8_t, state->size); - if (tevent_req_nomem(state->buf, req)) { - return; - } - } - memcpy(state->buf + state->received, buf, received); - state->received += received; - - TALLOC_FREE(subreq); - - if (state->received >= state->size) { - tevent_req_done(req); - return; - } - - subreq = cli_read_andx_send(state, state->ev, state->cli, state->fnum, - state->start_offset + state->received, - state->size - state->received); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, cli_readall_done, req); -} - -static NTSTATUS cli_readall_recv(struct tevent_req *req, ssize_t *received, - uint8_t **rcvbuf) -{ - struct cli_readall_state *state = tevent_req_data( - req, struct cli_readall_state); - NTSTATUS status; - - if (tevent_req_is_nterror(req, &status)) { - return status; - } - *received = state->received; - *rcvbuf = state->buf; - return NT_STATUS_OK; -} - struct cli_pull_chunk; struct cli_pull_state { -- 1.8.3 From 306632a97d4e80cdc76759fb21fbb30fe5eb7d81 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 10:46:28 +0200 Subject: [PATCH 23/70] s3:client: use the default io size Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 9b4692f2d057f31f76db0bdf7c4a515db057e2dd) --- source3/client/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/client/client.c b/source3/client/client.c index d09d012..5ec2948 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -55,7 +55,7 @@ static bool grepable = false; static char *cmdstr = NULL; const char *cmd_ptr = NULL; -static int io_bufsize = 524288; +static int io_bufsize = 0; /* we use the default size */ static int name_type = 0x20; static int max_protocol = -1; -- 1.8.3 From 73e547cd620b9c8cb3432b83db2894e372956edb Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 10:47:11 +0200 Subject: [PATCH 24/70] s3:client: fix compiler warning Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 2394f8788d2f6e21064db0b6099a0dbe3a33e1d6) --- source3/client/client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/client/client.c b/source3/client/client.c index 5ec2948..e91db4a 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -5338,6 +5338,7 @@ static int do_message_op(struct user_auth_info *a_info) int main(int argc,char *argv[]) { + const char **const_argv = discard_const_p(const char *, argv); char *base_directory = NULL; int opt; char *query_host = NULL; @@ -5388,7 +5389,7 @@ static int do_message_op(struct user_auth_info *a_info) popt_common_set_auth_info(auth_info); /* skip argv(0) */ - pc = poptGetContext("smbclient", argc, (const char **) argv, long_options, 0); + pc = poptGetContext("smbclient", argc, const_argv, long_options, 0); poptSetOtherOptionHelp(pc, "service "); while ((opt = poptGetNextOpt(pc)) != -1) { -- 1.8.3 From 0fd39691d62e830c2beb2d110f128dd8d86a1cd1 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 13:48:55 -0700 Subject: [PATCH 25/70] s3:lib: Factor read_ea_list_entry() and read_nttrans_ea_list() out so they can be used by the SMB2 client code. Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit c80349e0fad7c182b0bddefed99a78d95323faca) --- source3/lib/util_ea.c | 126 +++++++++++++++++++++++++++++++++++++++++++++++++ source3/lib/util_ea.h | 36 ++++++++++++++ source3/smbd/nttrans.c | 44 +---------------- source3/smbd/trans2.c | 62 +----------------------- source3/wscript_build | 3 +- 5 files changed, 166 insertions(+), 105 deletions(-) create mode 100644 source3/lib/util_ea.c create mode 100644 source3/lib/util_ea.h diff --git a/source3/lib/util_ea.c b/source3/lib/util_ea.c new file mode 100644 index 0000000..81684da --- /dev/null +++ b/source3/lib/util_ea.c @@ -0,0 +1,126 @@ +/* + Unix SMB/CIFS implementation. + SMB Extended attribute buffer handling + Copyright (C) Jeremy Allison 2005-2013 + Copyright (C) Tim Prouty 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "lib/util_ea.h" + +/**************************************************************************** + Read one EA list entry from the buffer. +****************************************************************************/ + +struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used) +{ + struct ea_list *eal = talloc_zero(ctx, struct ea_list); + uint16 val_len; + unsigned int namelen; + size_t converted_size; + + if (!eal) { + return NULL; + } + + if (data_size < 6) { + return NULL; + } + + eal->ea.flags = CVAL(pdata,0); + namelen = CVAL(pdata,1); + val_len = SVAL(pdata,2); + + if (4 + namelen + 1 + val_len > data_size) { + return NULL; + } + + /* Ensure the name is null terminated. */ + if (pdata[namelen + 4] != '\0') { + return NULL; + } + if (!pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4, &converted_size)) { + DEBUG(0,("read_ea_list_entry: pull_ascii_talloc failed: %s", + strerror(errno))); + } + if (!eal->ea.name) { + return NULL; + } + + eal->ea.value = data_blob_talloc(eal, NULL, (size_t)val_len + 1); + if (!eal->ea.value.data) { + return NULL; + } + + memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len); + + /* Ensure we're null terminated just in case we print the value. */ + eal->ea.value.data[val_len] = '\0'; + /* But don't count the null. */ + eal->ea.value.length--; + + if (pbytes_used) { + *pbytes_used = 4 + namelen + 1 + val_len; + } + + DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name)); + dump_data(10, eal->ea.value.data, eal->ea.value.length); + + return eal; +} + +/**************************************************************************** + Read a list of EA names and data from an incoming data buffer. Create an ea_list with them. +****************************************************************************/ + +struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size) +{ + struct ea_list *ea_list_head = NULL; + size_t offset = 0; + + if (data_size < 4) { + return NULL; + } + + while (offset + 4 <= data_size) { + size_t next_offset = IVAL(pdata,offset); + struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset + 4, data_size - offset - 4, NULL); + + if (!eal) { + return NULL; + } + + DLIST_ADD_END(ea_list_head, eal, struct ea_list *); + if (next_offset == 0) { + break; + } + + /* Integer wrap protection for the increment. */ + if (offset + next_offset < offset) { + break; + } + + offset += next_offset; + + /* Integer wrap protection for while loop. */ + if (offset + 4 < offset) { + break; + } + + } + + return ea_list_head; +} diff --git a/source3/lib/util_ea.h b/source3/lib/util_ea.h new file mode 100644 index 0000000..54423ac --- /dev/null +++ b/source3/lib/util_ea.h @@ -0,0 +1,36 @@ +/* + Unix SMB/CIFS implementation. + SMB Extended attribute buffer handling + Copyright (C) Jeremy Allison 2005-2013 + Copyright (C) Tim Prouty 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __LIB_UTIL_EA_H__ +#define __LIB_UTIL_EA_H__ + +/**************************************************************************** + Read one EA list entry from a buffer. +****************************************************************************/ + +struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used); + +/**************************************************************************** + Read a list of EA names and data from an incoming data buffer. Create an ea_list with them. +****************************************************************************/ + +struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size); + +#endif /* __LIB_UTIL_EA_H__ */ diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index f4b0456..42cd25b 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -29,6 +29,7 @@ #include "auth.h" #include "smbprofile.h" #include "libsmb/libsmb.h" +#include "lib/util_ea.h" extern const struct generic_mapping file_generic_mapping; @@ -965,49 +966,6 @@ NTSTATUS set_sd_blob(files_struct *fsp, uint8_t *data, uint32_t sd_len, } /**************************************************************************** - Read a list of EA names and data from an incoming data buffer. Create an ea_list with them. -****************************************************************************/ - -struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size) -{ - struct ea_list *ea_list_head = NULL; - size_t offset = 0; - - if (data_size < 4) { - return NULL; - } - - while (offset + 4 <= data_size) { - size_t next_offset = IVAL(pdata,offset); - struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset + 4, data_size - offset - 4, NULL); - - if (!eal) { - return NULL; - } - - DLIST_ADD_END(ea_list_head, eal, struct ea_list *); - if (next_offset == 0) { - break; - } - - /* Integer wrap protection for the increment. */ - if (offset + next_offset < offset) { - break; - } - - offset += next_offset; - - /* Integer wrap protection for while loop. */ - if (offset + 4 < offset) { - break; - } - - } - - return ea_list_head; -} - -/**************************************************************************** Reply to a NT_TRANSACT_CREATE call (needs to process SD's). ****************************************************************************/ diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 61063d6..5c18c1b 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -39,6 +39,7 @@ #include "smbprofile.h" #include "rpc_server/srv_pipe_hnd.h" #include "printing.h" +#include "lib/util_ea.h" #define DIR_ENTRY_SAFETY_MARGIN 4096 @@ -750,67 +751,6 @@ static struct ea_list *read_ea_name_list(TALLOC_CTX *ctx, const char *pdata, siz } /**************************************************************************** - Read one EA list entry from the buffer. -****************************************************************************/ - -struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used) -{ - struct ea_list *eal = talloc_zero(ctx, struct ea_list); - uint16 val_len; - unsigned int namelen; - size_t converted_size; - - if (!eal) { - return NULL; - } - - if (data_size < 6) { - return NULL; - } - - eal->ea.flags = CVAL(pdata,0); - namelen = CVAL(pdata,1); - val_len = SVAL(pdata,2); - - if (4 + namelen + 1 + val_len > data_size) { - return NULL; - } - - /* Ensure the name is null terminated. */ - if (pdata[namelen + 4] != '\0') { - return NULL; - } - if (!pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4, &converted_size)) { - DEBUG(0,("read_ea_list_entry: pull_ascii_talloc failed: %s", - strerror(errno))); - } - if (!eal->ea.name) { - return NULL; - } - - eal->ea.value = data_blob_talloc(eal, NULL, (size_t)val_len + 1); - if (!eal->ea.value.data) { - return NULL; - } - - memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len); - - /* Ensure we're null terminated just in case we print the value. */ - eal->ea.value.data[val_len] = '\0'; - /* But don't count the null. */ - eal->ea.value.length--; - - if (pbytes_used) { - *pbytes_used = 4 + namelen + 1 + val_len; - } - - DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name)); - dump_data(10, eal->ea.value.data, eal->ea.value.length); - - return eal; -} - -/**************************************************************************** Read a list of EA names and data from an incoming data buffer. Create an ea_list with them. ****************************************************************************/ diff --git a/source3/wscript_build b/source3/wscript_build index 116aee2..c636df1 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -67,7 +67,8 @@ LIB_SRC = ''' lib/fncall.c libads/krb5_errs.c lib/system_smbd.c lib/audit.c lib/tevent_wait.c - lib/idmap_cache.c''' + lib/idmap_cache.c + lib/util_ea.c''' LIB_UTIL_SRC = ''' lib/system.c -- 1.8.3 From 321fef2c327eeb85f364d53a3e10948d2063943c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 15:54:05 -0700 Subject: [PATCH 26/70] s3:libsmb: Add in the core of the libsmb client SMB2 functions. These create a synchronous cli_smb2_XXX() style interface designed to plug directly into the libsmb/cliXXXX.c code. https://bugzilla.samba.org/show_bug.cgi?id=9974 Signed-off-by: Jeremy Allison Signed-off-by: Stefan Metzmacher (cherry picked from commit 28591dfd5d2163d9181d45d64a4a750e335b7c56) --- source3/include/client.h | 1 + source3/libsmb/cli_smb2_fnum.c | 2373 ++++++++++++++++++++++++++++++++++++++++ source3/libsmb/cli_smb2_fnum.h | 161 +++ source3/libsmb/clirap.c | 7 +- source3/libsmb/clirap.h | 4 + source3/libsmb/libsmb.h | 1 + source3/wscript_build | 3 +- 7 files changed, 2543 insertions(+), 7 deletions(-) create mode 100644 source3/libsmb/cli_smb2_fnum.c create mode 100644 source3/libsmb/cli_smb2_fnum.h diff --git a/source3/include/client.h b/source3/include/client.h index 52e2212..09f9660 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -109,6 +109,7 @@ struct cli_state { struct { struct smbXcli_session *session; struct smbXcli_tcon *tcon; + struct idr_context *open_handles; } smb2; }; diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c new file mode 100644 index 0000000..d0b744b --- /dev/null +++ b/source3/libsmb/cli_smb2_fnum.c @@ -0,0 +1,2373 @@ +/* + Unix SMB/CIFS implementation. + smb2 lib + Copyright (C) Jeremy Allison 2013 + Copyright (C) Volker Lendecke 2013 + Copyright (C) Stefan Metzmacher 2013 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* + This code is a thin wrapper around the existing + cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c, + but allows the handles to be mapped to uint16_t fnums, + which are easier for smbclient to use. +*/ + +#include "includes.h" +#include "client.h" +#include "async_smb.h" +#include "../libcli/smb/smbXcli_base.h" +#include "smb2cli.h" +#include "cli_smb2_fnum.h" +#include "trans2.h" +#include "clirap.h" +#include "../libcli/smb/smb2_create_blob.h" +#include "libsmb/proto.h" +#include "lib/util/tevent_ntstatus.h" +#include "../libcli/security/security.h" +#include "lib/util_ea.h" + +struct smb2_hnd { + uint64_t fid_persistent; + uint64_t fid_volatile; +}; + +/* + * Handle mapping code. + */ + +/*************************************************************** + Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd. + Ensures handle is owned by cli struct. +***************************************************************/ + +static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli, + const struct smb2_hnd *ph, /* In */ + uint16_t *pfnum) /* Out */ +{ + int ret; + struct idr_context *idp = cli->smb2.open_handles; + struct smb2_hnd *owned_h = talloc_memdup(cli, + ph, + sizeof(struct smb2_hnd)); + + if (owned_h == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (idp == NULL) { + /* Lazy init */ + cli->smb2.open_handles = idr_init(cli); + if (cli->smb2.open_handles == NULL) { + TALLOC_FREE(owned_h); + return NT_STATUS_NO_MEMORY; + } + idp = cli->smb2.open_handles; + } + + ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE); + if (ret == -1) { + TALLOC_FREE(owned_h); + return NT_STATUS_NO_MEMORY; + } + + *pfnum = (uint16_t)ret; + return NT_STATUS_OK; +} + +/*************************************************************** + Return the smb2_hnd pointer associated with the given fnum. +***************************************************************/ + +static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli, + uint16_t fnum, /* In */ + struct smb2_hnd **pph) /* Out */ +{ + struct idr_context *idp = cli->smb2.open_handles; + + if (idp == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + *pph = (struct smb2_hnd *)idr_find(idp, fnum); + if (*pph == NULL) { + return NT_STATUS_INVALID_HANDLE; + } + return NT_STATUS_OK; +} + +/*************************************************************** + Delete the fnum to smb2_hnd mapping. Zeros out handle on + successful return. +***************************************************************/ + +static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli, + struct smb2_hnd **pph, /* In */ + uint16_t fnum) /* In */ +{ + struct idr_context *idp = cli->smb2.open_handles; + struct smb2_hnd *ph; + + if (idp == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + ph = (struct smb2_hnd *)idr_find(idp, fnum); + if (ph != *pph) { + return NT_STATUS_INVALID_PARAMETER; + } + idr_remove(idp, fnum); + TALLOC_FREE(*pph); + return NT_STATUS_OK; +} + +/*************************************************************** + Oplock mapping code. +***************************************************************/ + +static uint8_t flags_to_smb2_oplock(uint32_t create_flags) +{ + if (create_flags & REQUEST_BATCH_OPLOCK) { + return SMB2_OPLOCK_LEVEL_BATCH; + } else if (create_flags & REQUEST_OPLOCK) { + return SMB2_OPLOCK_LEVEL_EXCLUSIVE; + } + + /* create_flags doesn't do a level2 request. */ + return SMB2_OPLOCK_LEVEL_NONE; +} + +/*************************************************************** + Small wrapper that allows SMB2 create to return a uint16_t fnum. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_create_fnum(struct cli_state *cli, + const char *fname, + uint32_t create_flags, + uint32_t desired_access, + uint32_t file_attributes, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint16_t *pfid, + struct smb2_create_returns *cr) +{ + NTSTATUS status; + struct smb2_hnd h; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (cli->backup_intent) { + create_options |= FILE_OPEN_FOR_BACKUP_INTENT; + } + + /* SMB2 is pickier about pathnames. Ensure it doesn't + start in a '\' */ + if (*fname == '\\') { + fname++; + } + + status = smb2cli_create(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + fname, + flags_to_smb2_oplock(create_flags), + SMB2_IMPERSONATION_IMPERSONATION, + desired_access, + file_attributes, + share_access, + create_disposition, + create_options, + NULL, + &h.fid_persistent, + &h.fid_volatile, + cr); + + if (NT_STATUS_IS_OK(status)) { + status = map_smb2_handle_to_fnum(cli, &h, pfid); + } + + return status; +} + +/*************************************************************** + Small wrapper that allows SMB2 close to use a uint16_t fnum. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum) +{ + struct smb2_hnd *ph = NULL; + NTSTATUS status; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = smb2cli_close(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 0, + ph->fid_persistent, + ph->fid_volatile); + + /* Delete the fnum -> handle mapping. */ + if (NT_STATUS_IS_OK(status)) { + status = delete_smb2_handle_mapping(cli, &ph, fnum); + } + + return status; +} + +/*************************************************************** + Small wrapper that allows SMB2 to create a directory + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname) +{ + NTSTATUS status; + uint16_t fnum; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = cli_smb2_create_fnum(cli, + dname, + 0, /* create_flags */ + FILE_READ_ATTRIBUTES, /* desired_access */ + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */ + FILE_CREATE, /* create_disposition */ + FILE_DIRECTORY_FILE, /* create_options */ + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return cli_smb2_close_fnum(cli, fnum); +} + +/*************************************************************** + Small wrapper that allows SMB2 to delete a directory + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname) +{ + NTSTATUS status; + uint16_t fnum; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = cli_smb2_create_fnum(cli, + dname, + 0, /* create_flags */ + DELETE_ACCESS, /* desired_access */ + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */ + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return cli_smb2_close_fnum(cli, fnum); +} + +/*************************************************************** + Small wrapper that allows SMB2 to unlink a pathname. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname) +{ + NTSTATUS status; + uint16_t fnum; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = cli_smb2_create_fnum(cli, + fname, + 0, /* create_flags */ + DELETE_ACCESS, /* desired_access */ + FILE_ATTRIBUTE_NORMAL, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + FILE_DELETE_ON_CLOSE, /* create_options */ + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return cli_smb2_close_fnum(cli, fnum); +} + +/*************************************************************** + Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply. +***************************************************************/ + +static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data, + uint32_t dir_data_length, + struct file_info *finfo, + uint32_t *next_offset) +{ + size_t namelen = 0; + size_t slen = 0; + size_t ret = 0; + + if (dir_data_length < 4) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + *next_offset = IVAL(dir_data, 0); + + if (*next_offset > dir_data_length) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + if (*next_offset != 0) { + /* Ensure we only read what in this record. */ + dir_data_length = *next_offset; + } + + if (dir_data_length < 105) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + finfo->atime_ts = interpret_long_date((const char *)dir_data + 16); + finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24); + finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32); + finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0); + finfo->mode = CVAL(dir_data + 56, 0); + namelen = IVAL(dir_data + 60,0); + if (namelen > (dir_data_length - 104)) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + slen = SVAL(dir_data + 68, 0); + if (slen > 24) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + ret = pull_string_talloc(finfo, + dir_data, + FLAGS2_UNICODE_STRINGS, + &finfo->short_name, + dir_data + 70, + slen, + STR_UNICODE); + if (ret == (size_t)-1) { + /* Bad conversion. */ + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + ret = pull_string_talloc(finfo, + dir_data, + FLAGS2_UNICODE_STRINGS, + &finfo->name, + dir_data + 104, + namelen, + STR_UNICODE); + if (ret == (size_t)-1) { + /* Bad conversion. */ + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + return NT_STATUS_OK; +} + +/******************************************************************* + Given a filename - get its directory name +********************************************************************/ + +static bool windows_parent_dirname(TALLOC_CTX *mem_ctx, + const char *dir, + char **parent, + const char **name) +{ + char *p; + ptrdiff_t len; + + p = strrchr_m(dir, '\\'); /* Find final '\\', if any */ + + if (p == NULL) { + if (!(*parent = talloc_strdup(mem_ctx, "\\"))) { + return false; + } + if (name) { + *name = dir; + } + return true; + } + + len = p-dir; + + if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) { + return false; + } + (*parent)[len] = '\0'; + + if (name) { + *name = p+1; + } + return true; +} + +/*************************************************************** + Wrapper that allows SMB2 to list a directory. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_list(struct cli_state *cli, + const char *pathname, + NTSTATUS (*fn)(const char *, + struct file_info *, + const char *, + void *), + void *state) +{ + NTSTATUS status; + uint16_t fnum = -1; + char *parent_dir = NULL; + const char *mask = NULL; + struct smb2_hnd *ph = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *subframe = NULL; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + /* Get the directory name. */ + if (!windows_parent_dirname(frame, + pathname, + &parent_dir, + &mask)) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + status = cli_smb2_create_fnum(cli, + parent_dir, + 0, /* create_flags */ + SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */ + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */ + FILE_OPEN, /* create_disposition */ + FILE_DIRECTORY_FILE, /* create_options */ + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + do { + uint8_t *dir_data = NULL; + uint32_t dir_data_length = 0; + uint32_t next_offset = 0; + subframe = talloc_stackframe(); + + status = smb2cli_query_directory(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + SMB2_FIND_ID_BOTH_DIRECTORY_INFO, + 0, /* flags */ + 0, /* file_index */ + ph->fid_persistent, + ph->fid_volatile, + mask, + 0xffff, + subframe, + &dir_data, + &dir_data_length); + + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) { + break; + } + goto fail; + } + + do { + struct file_info *finfo = talloc_zero(subframe, + struct file_info); + + if (finfo == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + status = parse_finfo_id_both_directory_info(dir_data, + dir_data_length, + finfo, + &next_offset); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = fn(cli->dfs_mountpoint, + finfo, + pathname, + state); + + if (!NT_STATUS_IS_OK(status)) { + break; + } + + TALLOC_FREE(finfo); + + /* Move to next entry. */ + if (next_offset) { + dir_data += next_offset; + dir_data_length -= next_offset; + } + } while (next_offset != 0); + + TALLOC_FREE(subframe); + + } while (NT_STATUS_IS_OK(status)); + + if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) { + status = NT_STATUS_OK; + } + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + TALLOC_FREE(subframe); + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to query a path info (basic level). + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli, + const char *name, + SMB_STRUCT_STAT *sbuf, + uint32_t *attributes) +{ + NTSTATUS status; + struct smb2_create_returns cr; + uint16_t fnum = -1; + size_t namelen = strlen(name); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* SMB2 is pickier about pathnames. Ensure it doesn't + end in a '\' */ + if (namelen > 0 && name[namelen-1] == '\\') { + char *modname = talloc_strdup(talloc_tos(), name); + modname[namelen-1] = '\0'; + name = modname; + } + + /* This is commonly used as a 'cd'. Try qpathinfo on + a directory handle first. */ + + status = cli_smb2_create_fnum(cli, + name, + 0, /* create_flags */ + FILE_READ_ATTRIBUTES, /* desired_access */ + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + FILE_DIRECTORY_FILE, /* create_options */ + &fnum, + &cr); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) { + /* Maybe a file ? */ + status = cli_smb2_create_fnum(cli, + name, + 0, /* create_flags */ + FILE_READ_ATTRIBUTES, /* desired_access */ + 0, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + 0, /* create_options */ + &fnum, + &cr); + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + cli_smb2_close_fnum(cli, fnum); + + ZERO_STRUCTP(sbuf); + + sbuf->st_ex_atime = nt_time_to_unix_timespec(&cr.last_access_time); + sbuf->st_ex_mtime = nt_time_to_unix_timespec(&cr.last_write_time); + sbuf->st_ex_ctime = nt_time_to_unix_timespec(&cr.change_time); + sbuf->st_ex_size = cr.end_of_file; + *attributes = cr.file_attributes; + + return NT_STATUS_OK; +} + +/*************************************************************** + Helper function for pathname operations. +***************************************************************/ + +static NTSTATUS get_fnum_from_path(struct cli_state *cli, + const char *name, + uint32_t desired_access, + uint16_t *pfnum) +{ + NTSTATUS status; + size_t namelen = strlen(name); + TALLOC_CTX *frame = talloc_stackframe(); + + /* SMB2 is pickier about pathnames. Ensure it doesn't + end in a '\' */ + if (namelen > 0 && name[namelen-1] == '\\') { + char *modname = talloc_strdup(frame, name); + if (modname == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + modname[namelen-1] = '\0'; + name = modname; + } + + /* Try to open a file handle first. */ + status = cli_smb2_create_fnum(cli, + name, + 0, /* create_flags */ + desired_access, + 0, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + 0, /* create_options */ + pfnum, + NULL); + + if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) { + status = cli_smb2_create_fnum(cli, + name, + 0, /* create_flags */ + desired_access, + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + FILE_DIRECTORY_FILE, /* create_options */ + pfnum, + NULL); + } + + fail: + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to query a path info (ALTNAME level). + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli, + const char *name, + fstring alt_name) +{ + NTSTATUS status; + DATA_BLOB outbuf = data_blob_null; + uint16_t fnum = -1; + struct smb2_hnd *ph = NULL; + uint32_t altnamelen = 0; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_READ_ATTRIBUTES, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1), + level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */ + + status = smb2cli_query_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + 0, /* in_additional_info */ + 0, /* in_flags */ + ph->fid_persistent, + ph->fid_volatile, + frame, + &outbuf); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Parse the reply. */ + if (outbuf.length < 4) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + altnamelen = IVAL(outbuf.data, 0); + if (altnamelen > outbuf.length - 4) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + if (altnamelen > 0) { + size_t ret = 0; + char *short_name = NULL; + ret = pull_string_talloc(frame, + outbuf.data, + FLAGS2_UNICODE_STRINGS, + &short_name, + outbuf.data + 4, + altnamelen, + STR_UNICODE); + if (ret == (size_t)-1) { + /* Bad conversion. */ + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + fstrcpy(alt_name, short_name); + } else { + alt_name[0] = '\0'; + } + + status = NT_STATUS_OK; + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + TALLOC_FREE(frame); + return status; +} + + +/*************************************************************** + Wrapper that allows SMB2 to query a fnum info (basic level). + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli, + uint16_t fnum, + uint16_t *mode, + off_t *size, + struct timespec *create_time, + struct timespec *access_time, + struct timespec *write_time, + struct timespec *change_time, + SMB_INO_T *ino) +{ + NTSTATUS status; + DATA_BLOB outbuf = data_blob_null; + struct smb2_hnd *ph = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1), + level 0x12 (SMB2_FILE_ALL_INFORMATION). */ + + status = smb2cli_query_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + 0, /* in_additional_info */ + 0, /* in_flags */ + ph->fid_persistent, + ph->fid_volatile, + frame, + &outbuf); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Parse the reply. */ + if (outbuf.length < 0x60) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + if (create_time) { + *create_time = interpret_long_date((const char *)outbuf.data + 0x0); + } + if (access_time) { + *access_time = interpret_long_date((const char *)outbuf.data + 0x8); + } + if (write_time) { + *write_time = interpret_long_date((const char *)outbuf.data + 0x10); + } + if (change_time) { + *change_time = interpret_long_date((const char *)outbuf.data + 0x18); + } + if (mode) { + uint32_t attr = IVAL(outbuf.data, 0x20); + *mode = (uint16_t)attr; + } + if (size) { + uint64_t file_size = BVAL(outbuf.data, 0x30); + *size = (off_t)file_size; + } + if (ino) { + uint64_t file_index = BVAL(outbuf.data, 0x40); + *ino = (SMB_INO_T)file_index; + } + + fail: + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to query an fnum. + Implement on top of cli_smb2_qfileinfo_basic(). + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_getattrE(struct cli_state *cli, + uint16_t fnum, + uint16_t *attr, + off_t *size, + time_t *change_time, + time_t *access_time, + time_t *write_time) +{ + struct timespec access_time_ts; + struct timespec write_time_ts; + struct timespec change_time_ts; + NTSTATUS status = cli_smb2_qfileinfo_basic(cli, + fnum, + attr, + size, + NULL, + &access_time_ts, + &write_time_ts, + &change_time_ts, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (change_time) { + *change_time = change_time_ts.tv_sec; + } + if (access_time) { + *access_time = access_time_ts.tv_sec; + } + if (write_time) { + *write_time = write_time_ts.tv_sec; + } + return NT_STATUS_OK; +} + +/*************************************************************** + Wrapper that allows SMB2 to get pathname attributes. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_getatr(struct cli_state *cli, + const char *name, + uint16_t *attr, + off_t *size, + time_t *write_time) +{ + NTSTATUS status; + uint16_t fnum = -1; + struct smb2_hnd *ph = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_READ_ATTRIBUTES, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + status = cli_smb2_getattrE(cli, + fnum, + attr, + size, + NULL, + NULL, + write_time); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to query a pathname info (basic level). + Implement on top of cli_smb2_qfileinfo_basic(). + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli, + const char *name, + struct timespec *create_time, + struct timespec *access_time, + struct timespec *write_time, + struct timespec *change_time, + off_t *size, + uint16_t *mode, + SMB_INO_T *ino) +{ + NTSTATUS status; + struct smb2_hnd *ph = NULL; + uint16_t fnum = -1; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_READ_ATTRIBUTES, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = cli_smb2_qfileinfo_basic(cli, + fnum, + mode, + size, + create_time, + access_time, + write_time, + change_time, + ino); + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to query pathname streams. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli, + const char *name, + TALLOC_CTX *mem_ctx, + unsigned int *pnum_streams, + struct stream_struct **pstreams) +{ + NTSTATUS status; + struct smb2_hnd *ph = NULL; + uint16_t fnum = -1; + DATA_BLOB outbuf = data_blob_null; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_READ_ATTRIBUTES, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1), + level 22 (SMB2_FILE_STREAM_INFORMATION). */ + + status = smb2cli_query_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + 0, /* in_additional_info */ + 0, /* in_flags */ + ph->fid_persistent, + ph->fid_volatile, + frame, + &outbuf); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Parse the reply. */ + if (!parse_streams_blob(mem_ctx, + outbuf.data, + outbuf.length, + pnum_streams, + pstreams)) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to set pathname attributes. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_setatr(struct cli_state *cli, + const char *name, + uint16_t attr, + time_t mtime) +{ + NTSTATUS status; + uint16_t fnum = -1; + struct smb2_hnd *ph = NULL; + uint8_t inbuf_store[40]; + DATA_BLOB inbuf = data_blob_null; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_WRITE_ATTRIBUTES, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1), + level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */ + + inbuf.data = inbuf_store; + inbuf.length = sizeof(inbuf_store); + data_blob_clear(&inbuf); + + SIVAL(inbuf.data,32,attr); + if (mtime != 0) { + put_long_date((char *)inbuf.data + 16,mtime); + } + /* Set all the other times to -1. */ + SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL); + SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL); + SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL); + + status = smb2cli_set_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */ + &inbuf, /* in_input_buffer */ + 0, /* in_additional_info */ + ph->fid_persistent, + ph->fid_volatile); + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to set file handle times. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_setattrE(struct cli_state *cli, + uint16_t fnum, + time_t change_time, + time_t access_time, + time_t write_time) +{ + NTSTATUS status; + struct smb2_hnd *ph = NULL; + uint8_t inbuf_store[40]; + DATA_BLOB inbuf = data_blob_null; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1), + level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */ + + inbuf.data = inbuf_store; + inbuf.length = sizeof(inbuf_store); + data_blob_clear(&inbuf); + + SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL); + if (change_time != 0) { + put_long_date((char *)inbuf.data + 24, change_time); + } + if (access_time != 0) { + put_long_date((char *)inbuf.data + 8, access_time); + } + if (write_time != 0) { + put_long_date((char *)inbuf.data + 16, write_time); + } + + return smb2cli_set_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */ + &inbuf, /* in_input_buffer */ + 0, /* in_additional_info */ + ph->fid_persistent, + ph->fid_volatile); +} + +/*************************************************************** + Wrapper that allows SMB2 to query disk attributes (size). + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail) +{ + NTSTATUS status; + uint16_t fnum = -1; + DATA_BLOB outbuf = data_blob_null; + struct smb2_hnd *ph = NULL; + uint32_t sectors_per_unit = 0; + uint32_t bytes_per_sector = 0; + uint64_t total_size = 0; + uint64_t size_free = 0; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + /* First open the top level directory. */ + status = cli_smb2_create_fnum(cli, + "", + 0, /* create_flags */ + FILE_READ_ATTRIBUTES, /* desired_access */ + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + FILE_DIRECTORY_FILE, /* create_options */ + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2), + level 3 (SMB_FS_SIZE_INFORMATION). */ + + status = smb2cli_query_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 2, /* in_info_type */ + 3, /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + 0, /* in_additional_info */ + 0, /* in_flags */ + ph->fid_persistent, + ph->fid_volatile, + frame, + &outbuf); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Parse the reply. */ + if (outbuf.length != 24) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + total_size = BVAL(outbuf.data, 0); + size_free = BVAL(outbuf.data, 8); + sectors_per_unit = IVAL(outbuf.data, 16); + bytes_per_sector = IVAL(outbuf.data, 20); + + if (bsize) { + *bsize = (int)(sectors_per_unit * bytes_per_sector); + } + if (total) { + *total = (int)total_size; + } + if (avail) { + *avail = (int)size_free; + } + + status = NT_STATUS_OK; + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to query a security descriptor. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli, + uint16_t fnum, + uint32_t sec_info, + TALLOC_CTX *mem_ctx, + struct security_descriptor **ppsd) +{ + NTSTATUS status; + DATA_BLOB outbuf = data_blob_null; + struct smb2_hnd *ph = NULL; + struct security_descriptor *lsd = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */ + + status = smb2cli_query_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 3, /* in_info_type */ + 0, /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + sec_info, /* in_additional_info */ + 0, /* in_flags */ + ph->fid_persistent, + ph->fid_volatile, + frame, + &outbuf); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Parse the reply. */ + status = unmarshall_sec_desc(mem_ctx, + outbuf.data, + outbuf.length, + &lsd); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + if (ppsd != NULL) { + *ppsd = lsd; + } else { + TALLOC_FREE(lsd); + } + + fail: + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to set a security descriptor. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli, + uint16_t fnum, + uint32_t sec_info, + const struct security_descriptor *sd) +{ + NTSTATUS status; + DATA_BLOB inbuf = data_blob_null; + struct smb2_hnd *ph = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = marshall_sec_desc(frame, + sd, + &inbuf.data, + &inbuf.length); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */ + + status = smb2cli_set_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 3, /* in_info_type */ + 0, /* in_file_info_class */ + &inbuf, /* in_input_buffer */ + sec_info, /* in_additional_info */ + ph->fid_persistent, + ph->fid_volatile); + + fail: + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to rename a file. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_rename(struct cli_state *cli, + const char *fname_src, + const char *fname_dst) +{ + NTSTATUS status; + DATA_BLOB inbuf = data_blob_null; + uint16_t fnum = -1; + struct smb2_hnd *ph = NULL; + smb_ucs2_t *converted_str = NULL; + size_t converted_size_bytes = 0; + size_t namelen = 0; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + fname_src, + DELETE_ACCESS, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* SMB2 is pickier about pathnames. Ensure it doesn't + start in a '\' */ + if (*fname_dst == '\\') { + fname_dst++; + } + + /* SMB2 is pickier about pathnames. Ensure it doesn't + end in a '\' */ + namelen = strlen(fname_dst); + if (namelen > 0 && fname_dst[namelen-1] == '\\') { + char *modname = talloc_strdup(frame, fname_dst); + modname[namelen-1] = '\0'; + fname_dst = modname; + } + + if (!push_ucs2_talloc(frame, + &converted_str, + fname_dst, + &converted_size_bytes)) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + /* W2K8 insists the dest name is not null + terminated. Remove the last 2 zero bytes + and reduce the name length. */ + + if (converted_size_bytes < 2) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + converted_size_bytes -= 2; + + inbuf = data_blob_talloc_zero(frame, + 20 + converted_size_bytes); + if (inbuf.data == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + SIVAL(inbuf.data, 16, converted_size_bytes); + memcpy(inbuf.data + 20, converted_str, converted_size_bytes); + + /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1), + level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */ + + status = smb2cli_set_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */ + &inbuf, /* in_input_buffer */ + 0, /* in_additional_info */ + ph->fid_persistent, + ph->fid_volatile); + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to set an EA on a fnum. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli, + uint16_t fnum, + const char *ea_name, + const char *ea_val, + size_t ea_len) +{ + NTSTATUS status; + DATA_BLOB inbuf = data_blob_null; + size_t bloblen = 0; + char *ea_name_ascii = NULL; + size_t namelen = 0; + struct smb2_hnd *ph = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Marshall the SMB2 EA data. */ + if (ea_len > 0xFFFF) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (!push_ascii_talloc(frame, + &ea_name_ascii, + ea_name, + &namelen)) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (namelen < 2 || namelen > 0xFF) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + bloblen = 8 + ea_len + namelen; + /* Round up to a 4 byte boundary. */ + bloblen = ((bloblen + 3)&~3); + + inbuf = data_blob_talloc_zero(frame, bloblen); + if (inbuf.data == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + /* namelen doesn't include the NULL byte. */ + SCVAL(inbuf.data, 5, namelen - 1); + SSVAL(inbuf.data, 6, ea_len); + memcpy(inbuf.data + 8, ea_name_ascii, namelen); + memcpy(inbuf.data + 8 + namelen, ea_val, ea_len); + + /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1), + level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */ + + status = smb2cli_set_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */ + &inbuf, /* in_input_buffer */ + 0, /* in_additional_info */ + ph->fid_persistent, + ph->fid_volatile); + + fail: + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to set an EA on a pathname. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli, + const char *name, + const char *ea_name, + const char *ea_val, + size_t ea_len) +{ + NTSTATUS status; + uint16_t fnum = -1; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_WRITE_EA, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = cli_set_ea_fnum(cli, + fnum, + ea_name, + ea_val, + ea_len); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to get an EA list on a pathname. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli, + const char *name, + TALLOC_CTX *ctx, + size_t *pnum_eas, + struct ea_struct **pea_array) +{ + NTSTATUS status; + uint16_t fnum = -1; + DATA_BLOB outbuf = data_blob_null; + struct smb2_hnd *ph = NULL; + struct ea_list *ea_list = NULL; + struct ea_list *eal = NULL; + size_t ea_count = 0; + TALLOC_CTX *frame = talloc_stackframe(); + + *pnum_eas = 0; + *pea_array = NULL; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_READ_EA, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1), + level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */ + + status = smb2cli_query_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + 0, /* in_additional_info */ + 0, /* in_flags */ + ph->fid_persistent, + ph->fid_volatile, + frame, + &outbuf); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Parse the reply. */ + ea_list = read_nttrans_ea_list(ctx, + (const char *)outbuf.data, + outbuf.length); + if (ea_list == NULL) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + /* Convert to an array. */ + for (eal = ea_list; eal; eal = eal->next) { + ea_count++; + } + + if (ea_count) { + *pea_array = talloc_array(ctx, struct ea_struct, ea_count); + if (*pea_array == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + ea_count = 0; + for (eal = ea_list; eal; eal = eal->next) { + (*pea_array)[ea_count++] = ea_list->ea; + } + *pnum_eas = ea_count; + } + + fail: + + TALLOC_FREE(frame); + return status; +} + +struct cli_smb2_read_state { + struct tevent_context *ev; + struct cli_state *cli; + struct smb2_hnd *ph; + uint64_t start_offset; + uint32_t size; + uint32_t received; + uint8_t *buf; +}; + +static void cli_smb2_read_done(struct tevent_req *subreq); + +struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + off_t offset, + size_t size) +{ + NTSTATUS status; + struct tevent_req *req, *subreq; + struct cli_smb2_read_state *state; + + req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + state->start_offset = (uint64_t)offset; + state->size = (uint32_t)size; + state->received = 0; + state->buf = NULL; + + status = map_fnum_to_smb2_handle(cli, + fnum, + &state->ph); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + subreq = smb2cli_read_send(state, + state->ev, + state->cli->conn, + state->cli->timeout, + state->cli->smb2.session, + state->cli->smb2.tcon, + state->size, + state->start_offset, + state->ph->fid_persistent, + state->ph->fid_volatile, + 0, /* minimum_count */ + 0); /* remaining_bytes */ + + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_smb2_read_done, req); + return req; +} + +static void cli_smb2_read_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb2_read_state *state = tevent_req_data( + req, struct cli_smb2_read_state); + NTSTATUS status; + + status = smb2cli_read_recv(subreq, state, + &state->buf, &state->received); + if (tevent_req_nterror(req, status)) { + return; + } + + if (state->received > state->size) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + tevent_req_done(req); +} + +NTSTATUS cli_smb2_read_recv(struct tevent_req *req, + ssize_t *received, + uint8_t **rcvbuf) +{ + NTSTATUS status; + struct cli_smb2_read_state *state = tevent_req_data( + req, struct cli_smb2_read_state); + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + /* + * As in cli_read_andx_recv() rcvbuf is talloced from the request, so + * better make sure that you copy it away before you talloc_free(req). + * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it! + */ + *received = (ssize_t)state->received; + *rcvbuf = state->buf; + return NT_STATUS_OK; +} + +struct cli_smb2_write_state { + struct tevent_context *ev; + struct cli_state *cli; + struct smb2_hnd *ph; + uint32_t flags; + const uint8_t *buf; + uint64_t offset; + uint32_t size; + uint32_t written; +}; + +static void cli_smb2_write_written(struct tevent_req *req); + +struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint16_t mode, + const uint8_t *buf, + off_t offset, + size_t size) +{ + NTSTATUS status; + struct tevent_req *req, *subreq = NULL; + struct cli_smb2_write_state *state = NULL; + + req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */ + state->flags = (uint32_t)mode; + state->buf = buf; + state->offset = (uint64_t)offset; + state->size = (uint32_t)size; + state->written = 0; + + status = map_fnum_to_smb2_handle(cli, + fnum, + &state->ph); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + subreq = smb2cli_write_send(state, + state->ev, + state->cli->conn, + state->cli->timeout, + state->cli->smb2.session, + state->cli->smb2.tcon, + state->size, + state->offset, + state->ph->fid_persistent, + state->ph->fid_volatile, + 0, /* remaining_bytes */ + state->flags, /* flags */ + state->buf); + + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_smb2_write_written, req); + return req; +} + +static void cli_smb2_write_written(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb2_write_state *state = tevent_req_data( + req, struct cli_smb2_write_state); + NTSTATUS status; + uint32_t written; + + status = smb2cli_write_recv(subreq, &written); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + state->written = written; + + tevent_req_done(req); +} + +NTSTATUS cli_smb2_write_recv(struct tevent_req *req, + size_t *pwritten) +{ + struct cli_smb2_write_state *state = tevent_req_data( + req, struct cli_smb2_write_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + if (pwritten != NULL) { + *pwritten = (size_t)state->written; + } + tevent_req_received(req); + return NT_STATUS_OK; +} + +/*************************************************************** + Wrapper that allows SMB2 async write using an fnum. + This is mostly cut-and-paste from Volker's code inside + source3/libsmb/clireadwrite.c, adapted for SMB2. + + Done this way so I can reuse all the logic inside cli_push() + for free :-). +***************************************************************/ + +struct cli_smb2_writeall_state { + struct tevent_context *ev; + struct cli_state *cli; + struct smb2_hnd *ph; + uint32_t flags; + const uint8_t *buf; + uint64_t offset; + uint32_t size; + uint32_t written; +}; + +static void cli_smb2_writeall_written(struct tevent_req *req); + +struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint16_t mode, + const uint8_t *buf, + off_t offset, + size_t size) +{ + NTSTATUS status; + struct tevent_req *req, *subreq = NULL; + struct cli_smb2_writeall_state *state = NULL; + uint32_t to_write; + uint32_t max_size; + bool ok; + + req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */ + state->flags = (uint32_t)mode; + state->buf = buf; + state->offset = (uint64_t)offset; + state->size = (uint32_t)size; + state->written = 0; + + status = map_fnum_to_smb2_handle(cli, + fnum, + &state->ph); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + to_write = state->size; + max_size = smb2cli_conn_max_write_size(state->cli->conn); + to_write = MIN(max_size, to_write); + ok = smb2cli_conn_req_possible(state->cli->conn, &max_size); + if (ok) { + to_write = MIN(max_size, to_write); + } + + subreq = smb2cli_write_send(state, + state->ev, + state->cli->conn, + state->cli->timeout, + state->cli->smb2.session, + state->cli->smb2.tcon, + to_write, + state->offset, + state->ph->fid_persistent, + state->ph->fid_volatile, + 0, /* remaining_bytes */ + state->flags, /* flags */ + state->buf + state->written); + + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_smb2_writeall_written, req); + return req; +} + +static void cli_smb2_writeall_written(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb2_writeall_state *state = tevent_req_data( + req, struct cli_smb2_writeall_state); + NTSTATUS status; + uint32_t written, to_write; + uint32_t max_size; + bool ok; + + status = smb2cli_write_recv(subreq, &written); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + state->written += written; + + if (state->written > state->size) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + to_write = state->size - state->written; + + if (to_write == 0) { + tevent_req_done(req); + return; + } + + max_size = smb2cli_conn_max_write_size(state->cli->conn); + to_write = MIN(max_size, to_write); + ok = smb2cli_conn_req_possible(state->cli->conn, &max_size); + if (ok) { + to_write = MIN(max_size, to_write); + } + + subreq = smb2cli_write_send(state, + state->ev, + state->cli->conn, + state->cli->timeout, + state->cli->smb2.session, + state->cli->smb2.tcon, + to_write, + state->offset + state->written, + state->ph->fid_persistent, + state->ph->fid_volatile, + 0, /* remaining_bytes */ + state->flags, /* flags */ + state->buf + state->written); + + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, cli_smb2_writeall_written, req); +} + +NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req, + size_t *pwritten) +{ + struct cli_smb2_writeall_state *state = tevent_req_data( + req, struct cli_smb2_writeall_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + if (pwritten != NULL) { + *pwritten = (size_t)state->written; + } + return NT_STATUS_OK; +} diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h new file mode 100644 index 0000000..0068686 --- /dev/null +++ b/source3/libsmb/cli_smb2_fnum.h @@ -0,0 +1,161 @@ +/* + Unix SMB/CIFS implementation. + smb2 wrapper client routines + Copyright (C) Jeremy Allison 2013 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __SMB2CLI_FNUM_H__ +#define __SMB2CLI_FNUM_H__ + +struct smbXcli_conn; +struct smbXcli_session; +struct cli_state; +struct file_info; + +NTSTATUS cli_smb2_create_fnum(struct cli_state *cli, + const char *fname, + uint32_t create_flags, + uint32_t desired_access, + uint32_t file_attributes, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint16_t *pfid, + struct smb2_create_returns *cr); + +NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum); +NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dirname); +NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dirname); +NTSTATUS cli_smb2_unlink(struct cli_state *cli,const char *fname); +NTSTATUS cli_smb2_list(struct cli_state *cli, + const char *pathname, + NTSTATUS (*fn)(const char *, + struct file_info *, + const char *, + void *), + void *state); +NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli, + const char *name, + SMB_STRUCT_STAT *sbuf, + uint32_t *attributes); +NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli, + const char *name, + fstring alt_name); +NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli, + uint16_t fnum, + uint16_t *mode, + off_t *size, + struct timespec *create_time, + struct timespec *access_time, + struct timespec *write_time, + struct timespec *change_time, + SMB_INO_T *ino); +NTSTATUS cli_smb2_getattrE(struct cli_state *cli, + uint16_t fnum, + uint16_t *attr, + off_t *size, + time_t *change_time, + time_t *access_time, + time_t *write_time); +NTSTATUS cli_smb2_getatr(struct cli_state *cli, + const char *name, + uint16_t *attr, + off_t *size, + time_t *write_time); +NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli, + const char *fname, + struct timespec *create_time, + struct timespec *access_time, + struct timespec *write_time, + struct timespec *change_time, + off_t *size, + uint16_t *mode, + SMB_INO_T *ino); +NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli, + const char *name, + TALLOC_CTX *mem_ctx, + unsigned int *pnum_streams, + struct stream_struct **pstreams); +NTSTATUS cli_smb2_setatr(struct cli_state *cli, + const char *fname, + uint16_t attr, + time_t mtime); +NTSTATUS cli_smb2_setattrE(struct cli_state *cli, + uint16_t fnum, + time_t change_time, + time_t access_time, + time_t write_time); +NTSTATUS cli_smb2_dskattr(struct cli_state *cli, + int *bsize, + int *total, + int *avail); +NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli, + uint16_t fnum, + uint32_t sec_info, + TALLOC_CTX *mem_ctx, + struct security_descriptor **ppsd); +NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli, + uint16_t fnum, + uint32_t sec_info, + const struct security_descriptor *sd); +NTSTATUS cli_smb2_rename(struct cli_state *cli, + const char *fname_src, + const char *fname_dst); +NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli, + uint16_t fnum, + const char *ea_name, + const char *ea_val, + size_t ea_len); +NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli, + const char *name, + TALLOC_CTX *ctx, + size_t *pnum_eas, + struct ea_struct **pea_list); +NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli, + const char *name, + const char *ea_name, + const char *ea_val, + size_t ea_len); +struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + off_t offset, + size_t size); +NTSTATUS cli_smb2_read_recv(struct tevent_req *req, + ssize_t *received, + uint8_t **rcvbuf); +struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint16_t mode, + const uint8_t *buf, + off_t offset, + size_t size); +NTSTATUS cli_smb2_write_recv(struct tevent_req *req, + size_t *pwritten); +struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint16_t mode, + const uint8_t *buf, + off_t offset, + size_t size); +NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req, + size_t *pwritten); +#endif /* __SMB2CLI_FNUM_H__ */ diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 77e2fa3..12a340c 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -879,11 +879,6 @@ NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname, Get the stream info ****************************************************************************/ -static bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *data, - size_t data_len, - unsigned int *pnum_streams, - struct stream_struct **pstreams); - struct cli_qpathinfo_streams_state { uint32_t num_data; uint8_t *data; @@ -986,7 +981,7 @@ NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname, return status; } -static bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata, +bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata, size_t data_len, unsigned int *pnum_streams, struct stream_struct **pstreams) diff --git a/source3/libsmb/clirap.h b/source3/libsmb/clirap.h index 91628ea..e105182 100644 --- a/source3/libsmb/clirap.h +++ b/source3/libsmb/clirap.h @@ -94,6 +94,10 @@ NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname, TALLOC_CTX *mem_ctx, unsigned int *pnum_streams, struct stream_struct **pstreams); +bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata, + size_t data_len, + unsigned int *pnum_streams, + struct stream_struct **pstreams); NTSTATUS cli_qfilename(struct cli_state *cli, uint16_t fnum, TALLOC_CTX *mem_ctx, char **name); NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum, diff --git a/source3/libsmb/libsmb.h b/source3/libsmb/libsmb.h index 061f317..6df06ae 100644 --- a/source3/libsmb/libsmb.h +++ b/source3/libsmb/libsmb.h @@ -26,5 +26,6 @@ #include "client.h" #include "libads/ads_status.h" #include "libsmb/proto.h" +#include "libsmb/cli_smb2_fnum.h" #endif /* _LIBSMB_LIBSMB_H */ diff --git a/source3/wscript_build b/source3/wscript_build index c636df1..e0432bf 100755 --- a/source3/wscript_build +++ b/source3/wscript_build @@ -135,7 +135,8 @@ LIBSMB_SRC = '''libsmb/clientgen.c libsmb/cliconnect.c libsmb/clifile.c libsmb/cli_np_tstream.c libsmb/reparse_symlink.c libsmb/clisymlink.c - libsmb/smbsock_connect.c''' + libsmb/smbsock_connect.c + libsmb/cli_smb2_fnum.c''' LIBMSRPC_SRC = ''' rpc_client/cli_pipe.c -- 1.8.3 From 759a4f24b59fe8437f9aa15ef0cfcb32f139b336 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 15:59:13 -0700 Subject: [PATCH 27/70] s3:libsmb: Plumb cli_smb2_rename() inside cli_rename(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit c748a959b40f184190cd537f0ad5f0772b484841) --- source3/libsmb/clifile.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 4b4e1a0..bfc3984 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1097,11 +1097,19 @@ NTSTATUS cli_rename_recv(struct tevent_req *req) NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_rename(cli, + fname_src, + fname_dst); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From 772daddfff1f3ba4bfffa42b6117532a8a62ed83 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:00:40 -0700 Subject: [PATCH 28/70] s3:libsmb: Plumb cli_smb2_unlink() inside cli_unlink(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 179c27dd0235c4949045eef2ffb7a87175a4483b) --- source3/libsmb/clifile.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index bfc3984..f2e4ac2 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1415,11 +1415,17 @@ NTSTATUS cli_unlink_recv(struct tevent_req *req) NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_unlink(cli, fname); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From 3f61de127e2a7fcece51316ca1bd298cf5d1ae20 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:01:49 -0700 Subject: [PATCH 29/70] s3:libsmb: Plumb cli_smb2_mkdir() inside cli_mkdir(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 46da267afd540fe2d31f1395cda9e2853cf6432a) --- source3/libsmb/clifile.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index f2e4ac2..9659fc1 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1525,11 +1525,17 @@ NTSTATUS cli_mkdir_recv(struct tevent_req *req) NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_mkdir(cli, dname); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From 3756304c56ff13a7c138e4ec77d31455a0c9de36 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:03:00 -0700 Subject: [PATCH 30/70] s3:libsmb: Plumb cli_smb2_rmdir() inside cli_rmdir(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 04d396566b90f32dc239450596ab50502f9cbb02) --- source3/libsmb/clifile.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 9659fc1..d63734d 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1635,11 +1635,17 @@ NTSTATUS cli_rmdir_recv(struct tevent_req *req) NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_rmdir(cli, dname); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From 7ef05e976f55331904caca50745ffec539148aad Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:06:19 -0700 Subject: [PATCH 31/70] s3:libsmb: Plumb cli_smb2_create_fnum() inside cli_ntcreate(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit c1c4491d5e5bb16c274fe4fe162156a7ec910b93) --- source3/libsmb/clifile.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index d63734d..3c799a6 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1914,11 +1914,26 @@ NTSTATUS cli_ntcreate(struct cli_state *cli, uint8_t SecurityFlags, uint16_t *pfid) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_create_fnum(cli, + fname, + CreatFlags, + DesiredAccess, + FileAttributes, + ShareAccess, + CreateDisposition, + CreateOptions, + pfid, + NULL); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From cf250a12fade735c18ea27208a12a0348ad6495c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:10:34 -0700 Subject: [PATCH 32/70] s3:libsmb: Plumb cli_smb2_close_fnum() inside cli_close(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 85f60cc3d8f68ce5eb687cc6e367bb66bdef8b99) --- source3/libsmb/clifile.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 3c799a6..571e1cc 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -2536,11 +2536,17 @@ NTSTATUS cli_close_recv(struct tevent_req *req) NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_close_fnum(cli, fnum); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From d77bce2116124ed692bce3b6f793c7c49748bc78 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:11:59 -0700 Subject: [PATCH 33/70] s3:libsmb: Plumb cli_smb2_getattrE() inside cli_getattrE(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 0bbc0446210fa504f9834de948c4d066df752666) --- source3/libsmb/clifile.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 571e1cc..e3fb62d 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -3379,11 +3379,23 @@ NTSTATUS cli_getattrE(struct cli_state *cli, time_t *access_time, time_t *write_time) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev = NULL; struct tevent_req *req = NULL; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_getattrE(cli, + fnum, + attr, + size, + change_time, + access_time, + write_time); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From 25490b0eac90b78fe0885414b13b0760de71706f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:14:47 -0700 Subject: [PATCH 34/70] s3:libsmb: Plumb cli_smb2_setattrE() inside cli_setattrE(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 83c410c99e3ef8db00dd002c1a1a93b0035cd2e7) --- source3/libsmb/clifile.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index e3fb62d..d0e9bb6 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -3647,11 +3647,21 @@ NTSTATUS cli_setattrE(struct cli_state *cli, time_t access_time, time_t write_time) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev = NULL; struct tevent_req *req = NULL; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_setattrE(cli, + fnum, + change_time, + access_time, + write_time); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From 9bfa9e67ab605c78e319be4bd8d6711f5362a5e8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:16:03 -0700 Subject: [PATCH 35/70] s3:libsmb: Plumb cli_smb2_setatr() inside cli_setatr(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit ea267a7e4b4c413336b2bf54eb53ffc8d1524b44) --- source3/libsmb/clifile.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index d0e9bb6..4ac7313 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -3786,11 +3786,20 @@ NTSTATUS cli_setatr(struct cli_state *cli, uint16_t attr, time_t mtime) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev = NULL; struct tevent_req *req = NULL; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_setatr(cli, + fname, + attr, + mtime); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From 1150f3a54ce7c64417407b30a0f928c42cff8f9f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 14 Aug 2013 14:37:11 -0700 Subject: [PATCH 36/70] s3:libsmb: Plumb cli_smb2_getatr() inside cli_getatr(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 75d2e18502ccb811c018535f3c5c7325bdf5e613) --- source3/libsmb/clifile.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 4ac7313..f674118 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -3538,11 +3538,21 @@ NTSTATUS cli_getatr(struct cli_state *cli, off_t *size, time_t *write_time) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev = NULL; struct tevent_req *req = NULL; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_getatr(cli, + fname, + attr, + size, + write_time); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From 52fe74d47953f14a095453a529ab1a1abe8cd5ea Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:17:12 -0700 Subject: [PATCH 37/70] s3:libsmb: Plumb cli_smb2_dskattr() inside cli_dskattr(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit c6ed0b88312d7e231749a09a87944caea4c9808e) --- source3/libsmb/clifile.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index f674118..77796d8 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -4034,11 +4034,17 @@ NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *a NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev = NULL; struct tevent_req *req = NULL; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_dskattr(cli, bsize, total, avail); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From 7a1dc923675dd4cbeeb6619875c97164a9690bdc Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:19:06 -0700 Subject: [PATCH 38/70] s3:libsmb: Fix cli_set_ea_path() to use frame instead of talloc_tos(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit c1aeada4dd1f165eb33354c5a4323ed1ebf453a9) --- source3/libsmb/clifile.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 77796d8..5cd1ff2 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -4322,9 +4322,10 @@ NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path, NTSTATUS status; TALLOC_CTX *frame = talloc_stackframe(); - param = talloc_array(talloc_tos(), uint8_t, 6); + param = talloc_array(frame, uint8_t, 6); if (!param) { - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto fail; } SSVAL(param,0,SMB_INFO_SET_EA); SSVAL(param,2,0); @@ -4337,7 +4338,10 @@ NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path, status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len, ea_name, ea_val, ea_len); - talloc_free(frame); + + fail: + + TALLOC_FREE(frame); return status; } -- 1.8.3 From 591f1c2e56ecf3c15151c8f46a461f743be17916 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:21:48 -0700 Subject: [PATCH 39/70] s3:libsmb: Plumb cli_smb2_set_ea_path() inside cli_set_ea_path(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 3276853e59c2686873baad7c6f9d2665ed6fdd56) --- source3/libsmb/clifile.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 5cd1ff2..2cfe7cd 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -4320,7 +4320,17 @@ NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path, unsigned int param_len = 0; uint8_t *param; NTSTATUS status; - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; + + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_set_ea_path(cli, + path, + ea_name, + ea_val, + ea_len); + } + + frame = talloc_stackframe(); param = talloc_array(frame, uint8_t, 6); if (!param) { -- 1.8.3 From 4734225ee7f27a5db340633ca8a79ba83e090df4 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:32:55 -0700 Subject: [PATCH 40/70] s3:libsmb: Plumb cli_smb2_set_ea_fnum() inside cli_set_ea_fnum(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit f8dfc50124e5b5083aa801d9658389dd3fa6698a) --- source3/libsmb/clifile.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 2cfe7cd..d186112 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -4365,6 +4365,14 @@ NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum, { uint8_t param[6]; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_set_ea_fnum(cli, + fnum, + ea_name, + ea_val, + ea_len); + } + memset(param, 0, 6); SSVAL(param,0,fnum); SSVAL(param,2,SMB_INFO_SET_EA); -- 1.8.3 From 524c4abcb59c84abb2342ee0024c56c799fc3ea0 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:42:02 -0700 Subject: [PATCH 41/70] s3:libsmb: Plumb cli_smb2_get_ea_list_path() inside cli_get_ea_list_path(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 7e2d969deb1d4bcf3add422d80852b2d386cfaac) --- source3/libsmb/clifile.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index d186112..424354b 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -4554,11 +4554,21 @@ NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path, size_t *pnum_eas, struct ea_struct **pea_list) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev = NULL; struct tevent_req *req = NULL; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_get_ea_list_path(cli, + path, + ctx, + pnum_eas, + pea_list); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From e985f0cc586169493c1b974b44484ab671daeea4 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:43:33 -0700 Subject: [PATCH 42/70] s3:libsmb: Plumb cli_smb2_list() inside cli_list(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 73255d3ba912b3a112f9d766deae895f51e16cd9) --- source3/libsmb/clilist.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c index b0d3a4e..ed970cd 100644 --- a/source3/libsmb/clilist.c +++ b/source3/libsmb/clilist.c @@ -933,7 +933,7 @@ NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16 attribute, NTSTATUS (*fn)(const char *, struct file_info *, const char *, void *), void *state) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; @@ -941,6 +941,12 @@ NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16 attribute, size_t i, num_finfo; uint16_t info_level; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_list(cli, mask, fn, state); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From 44347141c6756bf34b3e8a4de34b3895a2e72d83 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:45:05 -0700 Subject: [PATCH 43/70] s3:libsmb: Plumb cli_smb2_qpathinfo2() inside cli_qpathinfo2(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit f2f566b1cc8d55bd1cf93478b877a3e7f455855c) --- source3/libsmb/clirap.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 12a340c..41608dd 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -845,11 +845,25 @@ NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname, off_t *size, uint16 *mode, SMB_INO_T *ino) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_qpathinfo2(cli, + fname, + create_time, + access_time, + write_time, + change_time, + size, + mode, + ino); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From f01b0fe96ea882570ff7a67356052aa606efc052 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:46:05 -0700 Subject: [PATCH 44/70] s3:libsmb: Plumb cli_smb2_qpathinfo_streams() inside cli_qpathinfo_streams(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit e96309ca1b057d430444531523bb2c9f59fcd624) --- source3/libsmb/clirap.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 41608dd..bb4f334 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -965,11 +965,21 @@ NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname, unsigned int *pnum_streams, struct stream_struct **pstreams) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_qpathinfo_streams(cli, + fname, + mem_ctx, + pnum_streams, + pstreams); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From ec16e5059b14fb6f5d95e0cf65e2e153847b85fd Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:47:21 -0700 Subject: [PATCH 45/70] s3:libsmb: Plumb cli_smb2_qfileinfo_basic() inside cli_qfileinfo_basic(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 2bb3e251d59910d9bf527a73271094702bceefe2) --- source3/libsmb/clirap.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index bb4f334..06dea82 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -1149,6 +1149,18 @@ NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum, uint32_t num_rdata; NTSTATUS status; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_qfileinfo_basic(cli, + fnum, + mode, + size, + create_time, + access_time, + write_time, + change_time, + ino); + } + /* if its a win95 server then fail this - win95 totally screws it up */ if (cli->win95) { -- 1.8.3 From fadf34bc0010f1f77b296a75ea9bdb83e3af2989 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 10:52:02 -0700 Subject: [PATCH 46/70] s3:libsmb: Plumb cli_smb2_qpathinfo_basic() inside cli_qpathinfo_basic(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit cba3ed0466b8598e28a44809778b99e97b1bf1a1) --- source3/libsmb/clirap.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 06dea82..7a480d6 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -1275,11 +1275,20 @@ NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req, NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbuf, uint32 *attributes) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_qpathinfo_basic(cli, + name, + sbuf, + attributes); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.8.3 From fad147744b0c0cff7bc26dc0514c049afd11f614 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:50:03 -0700 Subject: [PATCH 47/70] s3:libsmb: Plumb cli_smb2_qpathinfo_alt_name() inside cli_qpathinfo_alt_name(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit de895bf228432f2a42bcdcadcf12ffd1be64022f) --- source3/libsmb/clirap.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 7a480d6..d6d2fae 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -1326,6 +1326,12 @@ NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstrin size_t converted_size = 0; NTSTATUS status; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_qpathinfo_alt_name(cli, + fname, + alt_name); + } + status = cli_qpathinfo(talloc_tos(), cli, fname, SMB_QUERY_FILE_ALT_NAME_INFO, 4, CLI_BUFFER_SIZE, &rdata, &num_rdata); -- 1.8.3 From 1b9042b6fce21d76680b462bebc5c80e97cec9e6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 11:00:08 -0700 Subject: [PATCH 48/70] s3:libsmb: Plumb cli_smb2_query_security_descriptor() inside cli_query_security_descriptor(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 1db7e90451f31d75298508c19a859d98d56d7e7c) --- source3/libsmb/clisecdesc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source3/libsmb/clisecdesc.c b/source3/libsmb/clisecdesc.c index 24da39d..a82feab 100644 --- a/source3/libsmb/clisecdesc.c +++ b/source3/libsmb/clisecdesc.c @@ -20,6 +20,7 @@ #include "includes.h" #include "libsmb/libsmb.h" #include "../libcli/security/secdesc.h" +#include "../libcli/smb/smbXcli_base.h" NTSTATUS cli_query_security_descriptor(struct cli_state *cli, uint16_t fnum, @@ -33,6 +34,14 @@ NTSTATUS cli_query_security_descriptor(struct cli_state *cli, NTSTATUS status; struct security_descriptor *lsd; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_query_security_descriptor(cli, + fnum, + sec_info, + mem_ctx, + sd); + } + SIVAL(param, 0, fnum); SIVAL(param, 4, sec_info); -- 1.8.3 From e003126a5644a0f7439851786cdd704a81071f84 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 11:00:49 -0700 Subject: [PATCH 49/70] s3:libsmb: Plumb cli_smb2_set_security_descriptor() inside cli_set_security_descriptor(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 80758e4b07c87280e778ba161c2c9c4a2ee47853) --- source3/libsmb/clisecdesc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source3/libsmb/clisecdesc.c b/source3/libsmb/clisecdesc.c index a82feab..986610f 100644 --- a/source3/libsmb/clisecdesc.c +++ b/source3/libsmb/clisecdesc.c @@ -104,6 +104,13 @@ NTSTATUS cli_set_security_descriptor(struct cli_state *cli, size_t len; NTSTATUS status; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_set_security_descriptor(cli, + fnum, + sec_info, + sd); + } + status = marshall_sec_desc(talloc_tos(), sd, &data, &len); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("marshall_sec_desc failed: %s\n", -- 1.8.3 From 3b5ab285ca74744d6c0f64f8fbb91a2cc3286d63 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 16:33:30 +0200 Subject: [PATCH 50/70] s3:libsmb: add SMB2 support to cli_push* Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 6896bf0b28a07eb8ead5b3bd2bc50229aa59d439) --- source3/libsmb/clireadwrite.c | 66 ++++++++++++++++++++++++++++++++----------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 10dc79b..821bcb1 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -1120,7 +1120,11 @@ struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, state->priv = priv; state->next_offset = start_offset; - state->chunk_size = cli_write_max_bufsize(cli, mode, 14); + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + state->chunk_size = smb2cli_conn_max_write_size(cli->conn); + } else { + state->chunk_size = cli_write_max_bufsize(cli, mode, 14); + } if (state->chunk_size > page_size) { state->chunk_size &= ~(page_size - 1); } @@ -1257,21 +1261,47 @@ static void cli_push_chunk_ship(struct cli_push_chunk *chunk) ofs = chunk->ofs + chunk->tmp_size; size = chunk->total_size - chunk->tmp_size; - ok = smb1cli_conn_req_possible(state->cli->conn); - if (!ok) { - return; - } + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + uint32_t max_size; - chunk->subreq = cli_write_andx_send(chunk, - state->ev, - state->cli, - state->fnum, - state->mode, - buf, - ofs, - size); - if (tevent_req_nomem(chunk->subreq, req)) { - return; + ok = smb2cli_conn_req_possible(state->cli->conn, &max_size); + if (!ok) { + return; + } + + /* + * downgrade depending on the available credits + */ + size = MIN(max_size, size); + + chunk->subreq = cli_smb2_write_send(chunk, + state->ev, + state->cli, + state->fnum, + state->mode, + buf, + ofs, + size); + if (tevent_req_nomem(chunk->subreq, req)) { + return; + } + } else { + ok = smb1cli_conn_req_possible(state->cli->conn); + if (!ok) { + return; + } + + chunk->subreq = cli_write_andx_send(chunk, + state->ev, + state->cli, + state->fnum, + state->mode, + buf, + ofs, + size); + if (tevent_req_nomem(chunk->subreq, req)) { + return; + } } tevent_req_set_callback(chunk->subreq, cli_push_chunk_done, @@ -1296,7 +1326,11 @@ static void cli_push_chunk_done(struct tevent_req *subreq) chunk->subreq = NULL; - status = cli_write_andx_recv(subreq, &written); + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + status = cli_smb2_write_recv(subreq, &written); + } else { + status = cli_write_andx_recv(subreq, &written); + } TALLOC_FREE(subreq); if (tevent_req_nterror(req, status)) { return; -- 1.8.3 From ed7c867b1cbb809554983a18d66be6334da0a7c5 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 18:20:08 +0200 Subject: [PATCH 51/70] s3:libsmb: add SMB2 support to cli_pull* Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit a85d4511e6bc84938d60f090b44a5b1468ee4136) --- source3/libsmb/clireadwrite.c | 60 +++++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 821bcb1..d28c226 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -360,7 +360,11 @@ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - state->chunk_size = cli_read_max_bufsize(cli); + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + state->chunk_size = smb2cli_conn_max_read_size(cli->conn); + } else { + state->chunk_size = cli_read_max_bufsize(cli); + } if (state->chunk_size > page_size) { state->chunk_size &= ~(page_size - 1); } @@ -519,19 +523,43 @@ static void cli_pull_chunk_ship(struct cli_pull_chunk *chunk) ofs = chunk->ofs + chunk->tmp_size; size = chunk->total_size - chunk->tmp_size; - ok = smb1cli_conn_req_possible(state->cli->conn); - if (!ok) { - return; - } + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + uint32_t max_size; - chunk->subreq = cli_read_andx_send(chunk, - state->ev, - state->cli, - state->fnum, - ofs, - size); - if (tevent_req_nomem(chunk->subreq, req)) { - return; + ok = smb2cli_conn_req_possible(state->cli->conn, &max_size); + if (!ok) { + return; + } + + /* + * downgrade depending on the available credits + */ + size = MIN(max_size, size); + + chunk->subreq = cli_smb2_read_send(chunk, + state->ev, + state->cli, + state->fnum, + ofs, + size); + if (tevent_req_nomem(chunk->subreq, req)) { + return; + } + } else { + ok = smb1cli_conn_req_possible(state->cli->conn); + if (!ok) { + return; + } + + chunk->subreq = cli_read_andx_send(chunk, + state->ev, + state->cli, + state->fnum, + ofs, + size); + if (tevent_req_nomem(chunk->subreq, req)) { + return; + } } tevent_req_set_callback(chunk->subreq, cli_pull_chunk_done, @@ -557,7 +585,11 @@ static void cli_pull_chunk_done(struct tevent_req *subreq) chunk->subreq = NULL; - status = cli_read_andx_recv(subreq, &received, &buf); + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + status = cli_smb2_read_recv(subreq, &received, &buf); + } else { + status = cli_read_andx_recv(subreq, &received, &buf); + } if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) { received = 0; status = NT_STATUS_OK; -- 1.8.3 From b7874e90839f177d2131c0db6b757a164bd0e56f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 18:38:57 +0200 Subject: [PATCH 52/70] s3:libsmb: add support for SMB2 in cli_writeall() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit ccf7b3719121e03ed06d15b9af5373eecba3e828) --- source3/libsmb/clireadwrite.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index d28c226..adcd98b 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -1066,7 +1066,13 @@ NTSTATUS cli_writeall(struct cli_state *cli, uint16_t fnum, uint16_t mode, if (ev == NULL) { goto fail; } - req = cli_writeall_send(frame, ev, cli, fnum, mode, buf, offset, size); + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + req = cli_smb2_writeall_send(frame, ev, cli, fnum, mode, + buf, offset, size); + } else { + req = cli_writeall_send(frame, ev, cli, fnum, mode, + buf, offset, size); + } if (req == NULL) { goto fail; } @@ -1074,7 +1080,11 @@ NTSTATUS cli_writeall(struct cli_state *cli, uint16_t fnum, uint16_t mode, status = map_nt_error_from_unix(errno); goto fail; } - status = cli_writeall_recv(req, pwritten); + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + status = cli_smb2_writeall_recv(req, pwritten); + } else { + status = cli_writeall_recv(req, pwritten); + } fail: TALLOC_FREE(frame); return status; -- 1.8.3 From 7c995fafedd57edef2fc6a0e5ce02ccf48a97c85 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 11:38:22 +0200 Subject: [PATCH 53/70] s3:libsmb: make cli_tdis_send/recv static Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 80d4f64352c0ddacb9ee15d2b48a42a0b7929501) --- source3/libsmb/cliconnect.c | 4 ++-- source3/libsmb/proto.h | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index d74ea0e..98b3bf1 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2757,7 +2757,7 @@ struct cli_tdis_state { static void cli_tdis_done(struct tevent_req *subreq); -struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx, +static struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli) { @@ -2796,7 +2796,7 @@ static void cli_tdis_done(struct tevent_req *subreq) tevent_req_done(req); } -NTSTATUS cli_tdis_recv(struct tevent_req *req) +static NTSTATUS cli_tdis_recv(struct tevent_req *req) { return tevent_req_simple_recv_ntstatus(req); } diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index 48496c8..648bdda 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -75,10 +75,6 @@ NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share, const char *dev, const char *pass, int passlen); NTSTATUS cli_tree_connect(struct cli_state *cli, const char *share, const char *dev, const char *pass, int passlen); -struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct cli_state *cli); -NTSTATUS cli_tdis_recv(struct tevent_req *req); NTSTATUS cli_tdis(struct cli_state *cli); NTSTATUS cli_connect_nb(const char *host, const struct sockaddr_storage *dest_ss, uint16_t port, int name_type, const char *myname, -- 1.8.3 From af8dcfb0ae5e18d5287a3a890df76d8135e4f6d0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 11:44:10 +0200 Subject: [PATCH 54/70] s3:libsmb: only set tcon to invalid in smb2cli_tdis* This matches the behavior of cli_tdis*. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit d732e9aab3bbad3ea97f8b120e57b41152aaee3b) --- source3/libsmb/smb2cli_tcon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/smb2cli_tcon.c b/source3/libsmb/smb2cli_tcon.c index b3136fa..2467ce5 100644 --- a/source3/libsmb/smb2cli_tcon.c +++ b/source3/libsmb/smb2cli_tcon.c @@ -243,7 +243,8 @@ static void smb2cli_tdis_done(struct tevent_req *subreq) if (tevent_req_nterror(req, status)) { return; } - TALLOC_FREE(state->cli->smb2.tcon); + smb2cli_tcon_set_values(state->cli->smb2.tcon, NULL, + UINT32_MAX, 0, 0, 0, 0); tevent_req_done(req); } -- 1.8.3 From eb10a47f293774c9937957347fec15f9c03e2281 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 11:44:58 +0200 Subject: [PATCH 55/70] s3:libsmb: call smb2cli_tdis() from cli_tdis() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit e6be68fb5e4dc528f7365f3413b9b66090992f42) --- source3/libsmb/cliconnect.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 98b3bf1..0e5f8a9 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2807,6 +2807,10 @@ NTSTATUS cli_tdis(struct cli_state *cli) struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return smb2cli_tdis(cli); + } + if (smbXcli_conn_has_async_calls(cli->conn)) { return NT_STATUS_INVALID_PARAMETER; } -- 1.8.3 From 5b3eb985f7641652c73d3d9abc65720d7e786f53 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 11:48:40 +0200 Subject: [PATCH 56/70] s3:libsmb: make cli_ulogoff_send/recv static Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 1d7bdfc4feac35d92b003c3c78f502897ecc5d4e) --- source3/libsmb/cliconnect.c | 4 ++-- source3/libsmb/proto.h | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 0e5f8a9..f64f37e 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2245,7 +2245,7 @@ struct cli_ulogoff_state { static void cli_ulogoff_done(struct tevent_req *subreq); -struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx, +static struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli) { @@ -2288,7 +2288,7 @@ static void cli_ulogoff_done(struct tevent_req *subreq) tevent_req_done(req); } -NTSTATUS cli_ulogoff_recv(struct tevent_req *req) +static NTSTATUS cli_ulogoff_recv(struct tevent_req *req) { return tevent_req_simple_recv_ntstatus(req); } diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index 648bdda..a1389ff 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -54,10 +54,6 @@ struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli); NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req); -struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct cli_state *cli); -NTSTATUS cli_ulogoff_recv(struct tevent_req *req); NTSTATUS cli_ulogoff(struct cli_state *cli); struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx, struct tevent_context *ev, -- 1.8.3 From 73ebba5342585ee8d6d14960bc83d49bf788a657 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 15:18:47 -0700 Subject: [PATCH 57/70] s3:libsmb: call smb2cli_logoff() from cli_ulogoff() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Thu Aug 15 10:53:21 CEST 2013 on sn-devel-104 (cherry picked from commit b706ca6e55aa76d4da901c69d991969602facc3b) --- source3/libsmb/cliconnect.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index f64f37e..7ec3b56 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2299,6 +2299,18 @@ NTSTATUS cli_ulogoff(struct cli_state *cli) struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + status = smb2cli_logoff(cli->conn, + cli->timeout, + cli->smb2.session); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + smb2cli_session_set_id_and_flags(cli->smb2.session, + UINT64_MAX, 0); + return NT_STATUS_OK; + } + if (smbXcli_conn_has_async_calls(cli->conn)) { return NT_STATUS_INVALID_PARAMETER; } -- 1.8.3 From 11571c084a49952623e4dc2c1696ffb741aa05af Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 19 Aug 2013 22:36:02 +0200 Subject: [PATCH 58/70] libsmb: Fix a bunch of Coverity IDs (fnum != -1) is always true, even if fnum=-1 was initialized. fnum is a uint16, and the comparison first casts this to 65535, which is always != -1. Also change the initialization to make it clearer what is happening here. Signed-off-by: Volker Lendecke Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Tue Aug 20 00:52:36 CEST 2013 on sn-devel-104 (cherry picked from commit 4f96d5753ffe6c446c46676ba31cd2a3722890a0) --- source3/libsmb/cli_smb2_fnum.c | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c index d0b744b..18b03f3 100644 --- a/source3/libsmb/cli_smb2_fnum.c +++ b/source3/libsmb/cli_smb2_fnum.c @@ -493,7 +493,7 @@ NTSTATUS cli_smb2_list(struct cli_state *cli, void *state) { NTSTATUS status; - uint16_t fnum = -1; + uint16_t fnum = 0xffff; char *parent_dir = NULL; const char *mask = NULL; struct smb2_hnd *ph = NULL; @@ -618,7 +618,7 @@ NTSTATUS cli_smb2_list(struct cli_state *cli, fail: - if (fnum != -1) { + if (fnum != 0xffff) { cli_smb2_close_fnum(cli, fnum); } TALLOC_FREE(subframe); @@ -638,7 +638,7 @@ NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli, { NTSTATUS status; struct smb2_create_returns cr; - uint16_t fnum = -1; + uint16_t fnum = 0xffff; size_t namelen = strlen(name); if (smbXcli_conn_has_async_calls(cli->conn)) { @@ -772,7 +772,7 @@ NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli, { NTSTATUS status; DATA_BLOB outbuf = data_blob_null; - uint16_t fnum = -1; + uint16_t fnum = 0xffff; struct smb2_hnd *ph = NULL; uint32_t altnamelen = 0; TALLOC_CTX *frame = talloc_stackframe(); @@ -865,7 +865,7 @@ NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli, fail: - if (fnum != -1) { + if (fnum != 0xffff) { cli_smb2_close_fnum(cli, fnum); } TALLOC_FREE(frame); @@ -1026,7 +1026,7 @@ NTSTATUS cli_smb2_getatr(struct cli_state *cli, time_t *write_time) { NTSTATUS status; - uint16_t fnum = -1; + uint16_t fnum = 0xffff; struct smb2_hnd *ph = NULL; TALLOC_CTX *frame = talloc_stackframe(); @@ -1071,7 +1071,7 @@ NTSTATUS cli_smb2_getatr(struct cli_state *cli, fail: - if (fnum != -1) { + if (fnum != 0xffff) { cli_smb2_close_fnum(cli, fnum); } @@ -1097,7 +1097,7 @@ NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli, { NTSTATUS status; struct smb2_hnd *ph = NULL; - uint16_t fnum = -1; + uint16_t fnum = 0xffff; TALLOC_CTX *frame = talloc_stackframe(); if (smbXcli_conn_has_async_calls(cli->conn)) { @@ -1141,7 +1141,7 @@ NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli, fail: - if (fnum != -1) { + if (fnum != 0xffff) { cli_smb2_close_fnum(cli, fnum); } @@ -1162,7 +1162,7 @@ NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli, { NTSTATUS status; struct smb2_hnd *ph = NULL; - uint16_t fnum = -1; + uint16_t fnum = 0xffff; DATA_BLOB outbuf = data_blob_null; TALLOC_CTX *frame = talloc_stackframe(); @@ -1229,7 +1229,7 @@ NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli, fail: - if (fnum != -1) { + if (fnum != 0xffff) { cli_smb2_close_fnum(cli, fnum); } @@ -1248,7 +1248,7 @@ NTSTATUS cli_smb2_setatr(struct cli_state *cli, time_t mtime) { NTSTATUS status; - uint16_t fnum = -1; + uint16_t fnum = 0xffff; struct smb2_hnd *ph = NULL; uint8_t inbuf_store[40]; DATA_BLOB inbuf = data_blob_null; @@ -1311,7 +1311,7 @@ NTSTATUS cli_smb2_setatr(struct cli_state *cli, ph->fid_volatile); fail: - if (fnum != -1) { + if (fnum != 0xffff) { cli_smb2_close_fnum(cli, fnum); } @@ -1391,7 +1391,7 @@ NTSTATUS cli_smb2_setattrE(struct cli_state *cli, NTSTATUS cli_smb2_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail) { NTSTATUS status; - uint16_t fnum = -1; + uint16_t fnum = 0xffff; DATA_BLOB outbuf = data_blob_null; struct smb2_hnd *ph = NULL; uint32_t sectors_per_unit = 0; @@ -1482,7 +1482,7 @@ NTSTATUS cli_smb2_dskattr(struct cli_state *cli, int *bsize, int *total, int *av fail: - if (fnum != -1) { + if (fnum != 0xffff) { cli_smb2_close_fnum(cli, fnum); } @@ -1644,7 +1644,7 @@ NTSTATUS cli_smb2_rename(struct cli_state *cli, { NTSTATUS status; DATA_BLOB inbuf = data_blob_null; - uint16_t fnum = -1; + uint16_t fnum = 0xffff; struct smb2_hnd *ph = NULL; smb_ucs2_t *converted_str = NULL; size_t converted_size_bytes = 0; @@ -1739,7 +1739,7 @@ NTSTATUS cli_smb2_rename(struct cli_state *cli, fail: - if (fnum != -1) { + if (fnum != 0xffff) { cli_smb2_close_fnum(cli, fnum); } @@ -1852,7 +1852,7 @@ NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli, size_t ea_len) { NTSTATUS status; - uint16_t fnum = -1; + uint16_t fnum = 0xffff; if (smbXcli_conn_has_async_calls(cli->conn)) { /* @@ -1887,7 +1887,7 @@ NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli, fail: - if (fnum != -1) { + if (fnum != 0xffff) { cli_smb2_close_fnum(cli, fnum); } @@ -1906,7 +1906,7 @@ NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli, struct ea_struct **pea_array) { NTSTATUS status; - uint16_t fnum = -1; + uint16_t fnum = 0xffff; DATA_BLOB outbuf = data_blob_null; struct smb2_hnd *ph = NULL; struct ea_list *ea_list = NULL; -- 1.8.3 From d821b15f2d10c58a806f4dc81c24d85c1d0a3f48 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 11:45:43 -0700 Subject: [PATCH 59/70] Remove restrictions on setting iosize inside smbclient for SMB2 connections. Also remove the SMB1 restriction to minimum iosize of 16384 (0x4000): Now values >= 0 and <= 0xFFFF00 can be set for SMB1, 0 meaning server defined behaviour. 0 is the new default for iosize, both for SMB1 and SMB2. Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam (cherry picked from commit 25521c90859de0651216c459273b2ffd916ee299) --- source3/client/client.c | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/source3/client/client.c b/source3/client/client.c index e91db4a..3926460 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -4528,29 +4528,35 @@ int cmd_iosize(void) int iosize; if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) { - if (!smb_encrypt) { - d_printf("iosize or iosize 0x. " - "Minimum is 16384 (0x4000), " - "max is 16776960 (0xFFFF00)\n"); + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + if (!smb_encrypt) { + d_printf("iosize or iosize 0x. " + "Minimum is 0 (default), " + "max is 16776960 (0xFFFF00)\n"); + } else { + d_printf("iosize or iosize 0x. " + "(Encrypted connection) ," + "Minimum is 0 (default), " + "max is 130048 (0x1FC00)\n"); + } } else { - d_printf("iosize or iosize 0x. " - "(Encrypted connection) ," - "Minimum is 16384 (0x4000), " - "max is 130048 (0x1FC00)\n"); + d_printf("iosize or iosize 0x.\n"); } return 1; } iosize = strtol(buf,NULL,0); - if (smb_encrypt && (iosize < 0x4000 || iosize > 0xFC00)) { - d_printf("iosize out of range for encrypted " - "connection (min = 16384 (0x4000), " - "max = 130048 (0x1FC00)"); - return 1; - } else if (!smb_encrypt && (iosize < 0x4000 || iosize > 0xFFFF00)) { - d_printf("iosize out of range (min = 16384 (0x4000), " - "max = 16776960 (0xFFFF00)"); - return 1; + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + if (smb_encrypt && (iosize < 0 || iosize > 0xFC00)) { + d_printf("iosize out of range for encrypted " + "connection (min = 0 (default), " + "max = 130048 (0x1FC00)"); + return 1; + } else if (!smb_encrypt && (iosize < 0 || iosize > 0xFFFF00)) { + d_printf("iosize out of range (min = 0 (default), " + "max = 16776960 (0xFFFF00)"); + return 1; + } } io_bufsize = iosize; -- 1.8.3 From f6f5bf23448586d470b71a6762f46c040d3df03c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 10:44:34 -0700 Subject: [PATCH 60/70] As SMB3 has transport level encryption, allow smbclient -e to force encryted SMB3 transport. Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam (cherry picked from commit 81e1058e20bcfc1efab2b39dd7642d8dbbe0cb3b) --- libcli/smb/smbXcli_base.c | 21 +++++++++++++++++++++ libcli/smb/smbXcli_base.h | 1 + source3/libsmb/clidfs.c | 18 +++++++++++++++++- 3 files changed, 39 insertions(+), 1 deletion(-) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index b502f4f..f8ebf0b 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -4948,6 +4948,27 @@ NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session, return NT_STATUS_OK; } +NTSTATUS smb2cli_session_encryption_on(struct smbXcli_session *session) +{ + if (session->smb2->should_encrypt) { + return NT_STATUS_OK; + } + + if (session->conn->protocol < PROTOCOL_SMB2_24) { + return NT_STATUS_NOT_SUPPORTED; + } + + if (!(session->conn->smb2.server.capabilities & SMB2_CAP_ENCRYPTION)) { + return NT_STATUS_NOT_SUPPORTED; + } + + if (session->smb2->signing_key.data == NULL) { + return NT_STATUS_NOT_SUPPORTED; + } + session->smb2->should_encrypt = true; + return NT_STATUS_OK; +} + struct smbXcli_tcon *smbXcli_tcon_create(TALLOC_CTX *mem_ctx) { struct smbXcli_tcon *tcon; diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index a7cfcc3..3d93427 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -294,6 +294,7 @@ NTSTATUS smb2cli_session_create_channel(TALLOC_CTX *mem_ctx, NTSTATUS smb2cli_session_set_channel_key(struct smbXcli_session *session, const DATA_BLOB channel_key, const struct iovec *recv_iov); +NTSTATUS smb2cli_session_encryption_on(struct smbXcli_session *session); struct smbXcli_tcon *smbXcli_tcon_create(TALLOC_CTX *mem_ctx); uint16_t smb1cli_tcon_current_id(struct smbXcli_tcon *tcon); diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c index 1d92843..57126e6 100644 --- a/source3/libsmb/clidfs.c +++ b/source3/libsmb/clidfs.c @@ -48,7 +48,23 @@ NTSTATUS cli_cm_force_encryption(struct cli_state *c, const char *domain, const char *sharename) { - NTSTATUS status = cli_force_encryption(c, + NTSTATUS status; + + if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) { + status = smb2cli_session_encryption_on(c->smb2.session); + if (NT_STATUS_EQUAL(status,NT_STATUS_NOT_SUPPORTED)) { + d_printf("Encryption required and " + "server doesn't support " + "SMB3 encryption - failing connect\n"); + } else if (!NT_STATUS_IS_OK(status)) { + d_printf("Encryption required and " + "setup failed with error %s.\n", + nt_errstr(status)); + } + return status; + } + + status = cli_force_encryption(c, username, password, domain); -- 1.8.3 From 40fc6ce64764c8186491cd22773efb13fb020eb3 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 13:49:39 -0700 Subject: [PATCH 61/70] Add new "timeout" command and -t option to smbclient to set the per-operation timeout. This is needed as once SMB3 encryption is selected the server response time can be very slow when requesting large numbers (256) of large encrypted packets (1MB) from a Windows 2012 virtual machine. This allows clients to tune their allowable wait time. Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam (cherry picked from commit d9c88a56dc451be09e8c9fc9aa8857e312fcb444) --- source3/client/client.c | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/source3/client/client.c b/source3/client/client.c index 3926460..a9edbee 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -56,6 +56,7 @@ static char *cmdstr = NULL; const char *cmd_ptr = NULL; static int io_bufsize = 0; /* we use the default size */ +static int io_timeout = (CLIENT_TIMEOUT/1000); /* Per operation timeout (in seconds). */ static int name_type = 0x20; static int max_protocol = -1; @@ -4565,6 +4566,31 @@ int cmd_iosize(void) } /**************************************************************************** + timeout command +***************************************************************************/ + +static int cmd_timeout(void) +{ + TALLOC_CTX *ctx = talloc_tos(); + char *buf; + + if (!next_token_talloc(ctx, &cmd_ptr,&buf,NULL)) { + unsigned int old_timeout = cli_set_timeout(cli, 0); + cli_set_timeout(cli, old_timeout); + d_printf("timeout (per-operation timeout " + "in seconds - currently %u).\n", + old_timeout/1000); + return 1; + } + + io_timeout = strtol(buf,NULL,0); + cli_set_timeout(cli, io_timeout*1000); + d_printf("io_timeout per operation is now %d\n", io_timeout); + return 0; +} + + +/**************************************************************************** history ****************************************************************************/ static int cmd_history(void) @@ -4672,6 +4698,7 @@ static struct { {"symlink",cmd_symlink," create a UNIX symlink",{COMPL_REMOTE,COMPL_REMOTE}}, {"tar",cmd_tar,"tar [IXFqbgNan] current directory to/from ",{COMPL_NONE,COMPL_NONE}}, {"tarmode",cmd_tarmode," tar's behaviour towards archive bits",{COMPL_NONE,COMPL_NONE}}, + {"timeout",cmd_timeout,"timeout - set the per-operation timeout in seconds (default 20)",{COMPL_NONE,COMPL_NONE}}, {"translate",cmd_translate,"toggle text translation for printing",{COMPL_NONE,COMPL_NONE}}, {"unlock",cmd_unlock,"unlock : remove a POSIX lock",{COMPL_REMOTE,COMPL_REMOTE}}, {"volume",cmd_volume,"print the volume name",{COMPL_NONE,COMPL_NONE}}, @@ -4775,6 +4802,7 @@ static int process_command_string(const char *cmd_in) if (!NT_STATUS_IS_OK(status)) { return 1; } + cli_set_timeout(cli, io_timeout*1000); } while (cmd[0] != '\0') { @@ -5202,6 +5230,8 @@ static int process(const char *base_directory) return 1; } + cli_set_timeout(cli, io_timeout*1000); + if (base_directory && *base_directory) { rc = do_cd(base_directory); if (rc) { @@ -5236,6 +5266,7 @@ static int do_host_query(const char *query_host) return 1; } + cli_set_timeout(cli, io_timeout*1000); browse_host(true); /* Ensure that the host can do IPv4 */ @@ -5271,6 +5302,7 @@ static int do_host_query(const char *query_host) return 1; } + cli_set_timeout(cli, io_timeout*1000); list_servers(lp_workgroup()); cli_shutdown(cli); @@ -5297,6 +5329,7 @@ static int do_tar_op(const char *base_directory) if (!NT_STATUS_IS_OK(status)) { return 1; } + cli_set_timeout(cli, io_timeout*1000); } recurse=true; @@ -5332,6 +5365,7 @@ static int do_message_op(struct user_auth_info *a_info) return 1; } + cli_set_timeout(cli, io_timeout*1000); send_message(get_cmdline_auth_info_username(a_info)); cli_shutdown(cli); @@ -5368,6 +5402,7 @@ static int do_message_op(struct user_auth_info *a_info) { "directory", 'D', POPT_ARG_STRING, NULL, 'D', "Start from directory", "DIR" }, { "command", 'c', POPT_ARG_STRING, &cmdstr, 'c', "Execute semicolon separated commands" }, { "send-buffer", 'b', POPT_ARG_INT, &io_bufsize, 'b', "Changes the transmit/send buffer", "BYTES" }, + { "timeout", 't', POPT_ARG_INT, &io_timeout, 'b', "Changes the per-operation timeout", "SECONDS" }, { "port", 'p', POPT_ARG_INT, &port, 'p', "Port to connect to", "PORT" }, { "grepable", 'g', POPT_ARG_NONE, NULL, 'g', "Produce grepable output" }, { "browse", 'B', POPT_ARG_NONE, NULL, 'B', "Browse SMB servers using DNS" }, -- 1.8.3 From c478cd531829fa926fda76836cc6f92be98065fc Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:44:14 -0700 Subject: [PATCH 62/70] Add "max protocol" command line documentation for smbcacls. Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam (cherry picked from commit 646ed6884c91cde7c9aec6fdb1a25d0e6a0898d0) --- docs-xml/manpages/smbcacls.1.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs-xml/manpages/smbcacls.1.xml b/docs-xml/manpages/smbcacls.1.xml index 91a1806..fdc3f58 100644 --- a/docs-xml/manpages/smbcacls.1.xml +++ b/docs-xml/manpages/smbcacls.1.xml @@ -33,6 +33,7 @@ -U username -h -d + -m|--max-protocol LEVEL @@ -139,6 +140,19 @@ + -m|--max-protocol PROTOCOL_NAME + This allows the user to select the + highest SMB protocol level that smbcacls will use to + connect to the server. By default this is set to + NT1, which is the highest available SMB1 protocol. + To connect using SMB2 or SMB3 protocol, use the + strings SMB2 or SMB3 respectively. Note that to connect + to a Windows 2012 server with encrypted transport selecting + a max-protocol of SMB3 is required. + + + + -t|--test-args Don't actually do anything, only validate the correctness of -- 1.8.3 From 4adbc83a8dc249ccc2d0ded2e616c4fa83702311 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:45:26 -0700 Subject: [PATCH 63/70] Add "-e" encrypt transport command line option documentation for smbcacls. Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam (cherry picked from commit 5b60d95abc767131b97151f03d7f668c81e728cb) --- docs-xml/manpages/smbcacls.1.xml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/docs-xml/manpages/smbcacls.1.xml b/docs-xml/manpages/smbcacls.1.xml index fdc3f58..22b55cc 100644 --- a/docs-xml/manpages/smbcacls.1.xml +++ b/docs-xml/manpages/smbcacls.1.xml @@ -33,6 +33,7 @@ -U username -h -d + -e -m|--max-protocol LEVEL @@ -140,6 +141,18 @@ + -e + This command line parameter requires the remote + server support the UNIX extensions or that the SMB3 protocol has been selected. + Requests that the connection be encrypted. Negotiates SMB encryption using either + SMB3 or POSIX extensions via GSSAPI. Uses the given credentials for + the encryption negotiation (either kerberos or NTLMv1/v2 if given + domain/username/password triple. Fails the connection if encryption + cannot be negotiated. + + + + -m|--max-protocol PROTOCOL_NAME This allows the user to select the highest SMB protocol level that smbcacls will use to -- 1.8.3 From 2e44d52a52fb15ca6539c7a6a4b1fcd98f930f01 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:47:13 -0700 Subject: [PATCH 64/70] Expand on the documentation of -m max-protocol for SMB2/3 for smbclient. Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam (cherry picked from commit 252a6b6d8a27f4b8be61c6b091318ddb76776471) --- docs-xml/manpages/smbclient.1.xml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/docs-xml/manpages/smbclient.1.xml b/docs-xml/manpages/smbclient.1.xml index 328fd50..f3e0858 100644 --- a/docs-xml/manpages/smbclient.1.xml +++ b/docs-xml/manpages/smbclient.1.xml @@ -256,7 +256,14 @@ -m|--max-protocol protocol - This parameter sets the maximum protocol version announced by the client. + This allows the user to select the + highest SMB protocol level that smbclient will use to + connect to the server. By default this is set to + NT1, which is the highest available SMB1 protocol. + To connect using SMB2 or SMB3 protocol, use the + strings SMB2 or SMB3 respectively. Note that to connect + to a Windows 2012 server with encrypted transport selecting + a max-protocol of SMB3 is required. -- 1.8.3 From b024b8f229e665b084703781dde7681c9821630f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:48:18 -0700 Subject: [PATCH 65/70] Fix the documentation for --send-buffersize for the new default value of zero for smbclient. Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam (cherry picked from commit 659f5fecd69fb240c1a2ea385584c22d00476b59) --- docs-xml/manpages/smbclient.1.xml | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs-xml/manpages/smbclient.1.xml b/docs-xml/manpages/smbclient.1.xml index f3e0858..659da6e 100644 --- a/docs-xml/manpages/smbclient.1.xml +++ b/docs-xml/manpages/smbclient.1.xml @@ -316,10 +316,16 @@ -b|--send-buffer buffersize - This option changes the transmit/send buffer - size when getting or putting a file from/to the server. The default - is 65520 bytes. Setting this value smaller (to 1200 bytes) has been - observed to speed up file transfers to and from a Win9x server. + + When sending or receiving files, smbclient uses an + internal buffer sized by the maximum number of allowed requests + to the connected server. This command allows this size to be set to any + range between 0 (which means use the default server controlled size) bytes + and 16776960 (0xFFFF00) bytes. Using the server controlled size is the + most efficient as smbclient will pipeline as many simultaneous reads or + writes needed to keep the server as busy as possible. Setting this to + any other size will slow down the transfer. This can also be set + using the iosize command inside smbclient. -- 1.8.3 From 579857ce2f71a6b23d0176dadb77447a8a95064a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:49:41 -0700 Subject: [PATCH 66/70] Fix the documentation of the iosize command to explain the new zero default for smbclient. Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam (cherry picked from commit 90566fd0deb8768acc96b0a0bc573183c4db20ef) --- docs-xml/manpages/smbclient.1.xml | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/docs-xml/manpages/smbclient.1.xml b/docs-xml/manpages/smbclient.1.xml index 659da6e..2ed5357 100644 --- a/docs-xml/manpages/smbclient.1.xml +++ b/docs-xml/manpages/smbclient.1.xml @@ -707,12 +707,15 @@ iosize <bytes> - When sending or receiving files, smbclient uses an - internal memory buffer by default of size 64512 bytes. This command - allows this size to be set to any range between 16384 (0x4000) bytes - and 16776960 (0xFFFF00) bytes. Larger sizes may mean more efficient - data transfer as smbclient will try and use the most efficient - read and write calls for the connected server. + + When sending or receiving files, smbclient uses an + internal buffer sized by the maximum number of allowed requests + to the connected server. This command allows this size to be set to any + range between 0 (which means use the default server controlled size) bytes + and 16776960 (0xFFFF00) bytes. Using the server controlled size is the + most efficient as smbclient will pipeline as many simultaneous reads or + writes needed to keep the server as busy as possible. Setting this to + any other size will slow down the transfer. -- 1.8.3 From 79b731f666e181c3cfeecace961876fc7edaa0b1 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:53:45 -0700 Subject: [PATCH 67/70] Fix the documentation of --encrypt to explain SMB3 encryption for smbclient. Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam (cherry picked from commit 4044e2beb7145afb261c98e100574e4e842e1b9e) --- docs-xml/manpages/smbclient.1.xml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs-xml/manpages/smbclient.1.xml b/docs-xml/manpages/smbclient.1.xml index 2ed5357..6717f18 100644 --- a/docs-xml/manpages/smbclient.1.xml +++ b/docs-xml/manpages/smbclient.1.xml @@ -331,13 +331,14 @@ -e|--encrypt - This command line parameter requires the remote - server support the UNIX extensions. Request that the connection be - encrypted. This is new for Samba 3.2 and will only work with Samba - 3.2 or above servers. Negotiates SMB encryption using GSSAPI. Uses - the given credentials for the encryption negotiation (either kerberos - or NTLMv1/v2 if given domain/username/password triple. Fails the - connection if encryption cannot be negotiated. + + This command line parameter requires the remote + server support the UNIX extensions or that the SMB3 protocol has been selected. + Requests that the connection be encrypted. Negotiates SMB encryption using either + SMB3 or POSIX extensions via GSSAPI. Uses the given credentials for + the encryption negotiation (either kerberos or NTLMv1/v2 if given + domain/username/password triple. Fails the connection if encryption + cannot be negotiated. -- 1.8.3 From 5faed09fda2d644ef59087ef9f891fab0d1ca1be Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:56:22 -0700 Subject: [PATCH 68/70] Add documentation for the new -t parameter in smbclient. Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam (cherry picked from commit f7dc59b3ad293105756433ef52c67e195eb49361) --- docs-xml/manpages/smbclient.1.xml | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/docs-xml/manpages/smbclient.1.xml b/docs-xml/manpages/smbclient.1.xml index 6717f18..f71e516 100644 --- a/docs-xml/manpages/smbclient.1.xml +++ b/docs-xml/manpages/smbclient.1.xml @@ -37,6 +37,7 @@ -p port -R <name resolve order> -s <smb config file> + -t <per-operation timeout in seconds> -k -P -c <command> @@ -67,6 +68,7 @@ -p port -R <name resolve order> -s <smb config file> + -t <per-operation timeout in seconds> -T<c|x>IXFqgbNan -k @@ -348,6 +350,18 @@ &popt.common.connection; + -t|--timeout <timeout-seconds> + This allows the user to tune the default + timeout used for each SMB request. The default setting is + 20 seconds. Increase it if requests to the server sometimes + time out. This can happen when SMB3 encryption is selected + and smbclient is overwhelming the server with requests. + This can also be set using the timeout + command inside smbclient. + + + + -T|--tar tar options smbclient may be used to create tar(1) compatible backups of all the files on an SMB/CIFS -- 1.8.3 From 4d975d1bb927935f1c4da1a3073710ce734e7c37 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:57:34 -0700 Subject: [PATCH 69/70] Add documentation for the new internal command timeout to smbclient. Signed-off-by: Jeremy Allison Reviewed-by: Michael Adam Autobuild-User(master): Michael Adam Autobuild-Date(master): Wed Aug 21 19:24:06 CEST 2013 on sn-devel-104 (cherry picked from commit 8d0392f9f7973e72a6082d66f81180d19eb0a56f) --- docs-xml/manpages/smbclient.1.xml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs-xml/manpages/smbclient.1.xml b/docs-xml/manpages/smbclient.1.xml index f71e516..425cc4b 100644 --- a/docs-xml/manpages/smbclient.1.xml +++ b/docs-xml/manpages/smbclient.1.xml @@ -1072,6 +1072,16 @@ + timeout <per-operation timeout in seconds> + This allows the user to tune the default + timeout used for each SMB request. The default setting is + 20 seconds. Increase it if requests to the server sometimes + time out. This can happen when SMB3 encryption is selected + and smbclient is overwhelming the server with requests. + + + + unlock <filenum> <hex-start> <hex-len> This command depends on the server supporting the CIFS UNIX extensions and will fail if the server does not. Tries to unlock a POSIX -- 1.8.3 From 654a4fcda3e72346774d854a648d8440f2247ff5 Mon Sep 17 00:00:00 2001 From: Michael Adam Date: Wed, 21 Aug 2013 16:12:30 +0200 Subject: [PATCH 70/70] client: add missing newlines to error messages for invalid iosize parameter. Signed-off-by: Michael Adam Reviewed-by: Jeremy Allison Autobuild-User(master): Jeremy Allison Autobuild-Date(master): Wed Aug 21 21:49:45 CEST 2013 on sn-devel-104 (cherry picked from commit db1d0349c4d898141a39f515c690e21409448d56) --- source3/client/client.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/source3/client/client.c b/source3/client/client.c index a9edbee..0d1f5b4 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -4551,11 +4551,11 @@ int cmd_iosize(void) if (smb_encrypt && (iosize < 0 || iosize > 0xFC00)) { d_printf("iosize out of range for encrypted " "connection (min = 0 (default), " - "max = 130048 (0x1FC00)"); + "max = 130048 (0x1FC00)\n"); return 1; } else if (!smb_encrypt && (iosize < 0 || iosize > 0xFFFF00)) { d_printf("iosize out of range (min = 0 (default), " - "max = 16776960 (0xFFFF00)"); + "max = 16776960 (0xFFFF00)\n"); return 1; } } -- 1.8.3