From 5bf673ccd5e58302fe5b67562b43ce12c35651a9 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 15:17:01 -0700 Subject: [PATCH 01/69] 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 --- 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 b1bcc5e3f977fdcfae769a94d3ce28b836f4d13e Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:08:49 +0200 Subject: [PATCH 02/69] 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 --- 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 123f2da9257a84d3115469084ef94a797f7603a0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:10:13 +0200 Subject: [PATCH 03/69] 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 --- 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 67ffc4eede719e8bbc6062039491b84a950356d9 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:11:41 +0200 Subject: [PATCH 04/69] s3:lib: remove unused interpret_protocol() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 be3888c1d9620d3d942f1a97a1615d1efe092649 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 11:35:44 -0700 Subject: [PATCH 05/69] 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 --- 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 be605211374d606d9ecff166b81dcffad046fd5b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 9 Aug 2013 11:15:48 -0700 Subject: [PATCH 06/69] s3:libsmb: Ensure we ask for DEFAULT_SMB2_MAX_CREDITS on successful negprot. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 add93c1925091e16009423fb26f857b1d108dc96 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:46:34 +0200 Subject: [PATCH 07/69] 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 --- 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 63be3b3e1eac0bcf75f161f59d0f4cd06fa349c0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:48:31 +0200 Subject: [PATCH 08/69] 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 --- 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 275005c..2b124ba 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 bc884894f802cbd87f21f6233e103104abc05312 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 14:00:45 +0200 Subject: [PATCH 09/69] 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 --- 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 e15b1161269f063f5aba61ca2b562c482e3dbb1b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 14:01:36 +0200 Subject: [PATCH 10/69] 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 --- 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 0c5db1759b3ff1a62bd806e5a68267c5c8a8a314 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 11:43:16 -0700 Subject: [PATCH 11/69] 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 --- 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 2f1baa3cc98f0f49a284e168e38c603185a197fe Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 08:12:08 +0200 Subject: [PATCH 12/69] 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 --- 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 327fa73a64f281ed2467fa356795520b80dec252 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 14:41:24 -0700 Subject: [PATCH 13/69] libcli/smb: Fix smb2cli_write_recv() and smb2cli_write() to return the bytes written. Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 4cc7a25f1c592b039a940b266364d068a3ab5781 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 15:01:50 -0700 Subject: [PATCH 14/69] 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 --- 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 1cca58fff85f7a32cef19cfd9c647fe8bb184cdf Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 09:50:29 +0200 Subject: [PATCH 15/69] libcli/smb: calculate the credit charge on the input and output dyn_len Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 d18d464ef4b1efbf297114ddc1f00a7894046b34 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 09:54:42 +0200 Subject: [PATCH 16/69] libcli/smb: pass max_dyn_len to smb2cli_req_create() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 2ff612dc2a566203a0c3d6c36a8e091c2470d350 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 10:25:52 +0200 Subject: [PATCH 17/69] 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 --- 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 1766e1dbdbf16afc6cf6eca7b943745d06c1c9ab Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 14:05:05 +0200 Subject: [PATCH 18/69] libcli/smb: add smb1cli_conn_req_possible() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 314d1f9e34d09ebf702fb85daa212101235e2cdd Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 15:49:19 +0200 Subject: [PATCH 19/69] libcli/smb: add smb2cli_conn_req_possible() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 b5122d903404f68da7805b3ea8581273249d29ed Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 14:10:59 +0200 Subject: [PATCH 20/69] 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 --- 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 4fc3513c5c61218bc6d199c455ff29ed2af12433 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 18:03:50 +0200 Subject: [PATCH 21/69] 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 --- 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 f82401f0cb239476354c3736dbc263823020be2b Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 18:23:55 +0200 Subject: [PATCH 22/69] s3:libsmb: remove unused cli_readall* Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 4693b5f4d9663786f420a9c9dd373132de755260 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 10:46:28 +0200 Subject: [PATCH 23/69] s3:client: use the default io size Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 5baf7c0edc2e59f7d1324a6c21b92e65be069280 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 10:47:11 +0200 Subject: [PATCH 24/69] s3:client: fix compiler warning Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 a0a1b89b7c173baad634ddf4d2428c87d0696967 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 13:48:55 -0700 Subject: [PATCH 25/69] 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 --- 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 a216f15..830ef34 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -38,6 +38,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 @@ -749,67 +750,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 a8bdaf0..0f4bac6 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 67c7c1e1d9133d6bcba44e624c869a69dd23548c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 15:54:05 -0700 Subject: [PATCH 26/69] 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 --- 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 0f4bac6..ff631a6 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 27cd17c4ba810c62c05dc3f3fa754238316cd866 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 15:59:13 -0700 Subject: [PATCH 27/69] s3:libsmb: Plumb cli_smb2_rename() inside cli_rename(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 771751e4c743a00c257f3b5f103e2a5b87659ef4 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:00:40 -0700 Subject: [PATCH 28/69] s3:libsmb: Plumb cli_smb2_unlink() inside cli_unlink(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 9ffc9ed788c31c5ef52cd5daccf1c331f072d363 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:01:49 -0700 Subject: [PATCH 29/69] s3:libsmb: Plumb cli_smb2_mkdir() inside cli_mkdir(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 630d48622a33c345bdd3a8e36d07241814815569 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:03:00 -0700 Subject: [PATCH 30/69] s3:libsmb: Plumb cli_smb2_rmdir() inside cli_rmdir(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 00a597846b96856d3963af216ddab85c397f10f0 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:06:19 -0700 Subject: [PATCH 31/69] s3:libsmb: Plumb cli_smb2_create_fnum() inside cli_ntcreate(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 a282bf09354f92560c5f3ef91fc32d77931004e8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:10:34 -0700 Subject: [PATCH 32/69] s3:libsmb: Plumb cli_smb2_close_fnum() inside cli_close(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 d6961288452ce84c2a455d45a36b931caef36d1f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:11:59 -0700 Subject: [PATCH 33/69] s3:libsmb: Plumb cli_smb2_getattrE() inside cli_getattrE(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 8143bcc265847c57856265cf29de13f0b2444bea Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:14:47 -0700 Subject: [PATCH 34/69] s3:libsmb: Plumb cli_smb2_setattrE() inside cli_setattrE(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 5ee24dc8813967a505049849cada3e3e718e0ff2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:16:03 -0700 Subject: [PATCH 35/69] s3:libsmb: Plumb cli_smb2_setatr() inside cli_setatr(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 83c152f408132abdc9e8e5a8922a730747031235 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 14 Aug 2013 14:37:11 -0700 Subject: [PATCH 36/69] s3:libsmb: Plumb cli_smb2_getatr() inside cli_getatr(). Signed-off-by: Jeremy Allison --- 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 a5d45a4ad98b96a361425519943b8978e7c0a63d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:17:12 -0700 Subject: [PATCH 37/69] s3:libsmb: Plumb cli_smb2_dskattr() inside cli_dskattr(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 dd544abab3a8c18f8feb1c5b698b2c62eda161c3 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:19:06 -0700 Subject: [PATCH 38/69] s3:libsmb: Fix cli_set_ea_path() to use frame instead of talloc_tos(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 218491a26c7d321ed261b8d1969b5124ebb6f9da Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:21:48 -0700 Subject: [PATCH 39/69] s3:libsmb: Plumb cli_smb2_set_ea_path() inside cli_set_ea_path(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 87428d87896797f6b48999ea3cb880a67097ca66 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:32:55 -0700 Subject: [PATCH 40/69] s3:libsmb: Plumb cli_smb2_set_ea_fnum() inside cli_set_ea_fnum(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 811aa2df318e1c4edd7c4ed3a4a17f1f4aec95df Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:42:02 -0700 Subject: [PATCH 41/69] s3:libsmb: Plumb cli_smb2_get_ea_list_path() inside cli_get_ea_list_path(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 0f2b23d3921289f7b705db211cf6a389380b92dc Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:43:33 -0700 Subject: [PATCH 42/69] s3:libsmb: Plumb cli_smb2_list() inside cli_list(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 96e1789410c5b87433d83d96fba94f753fd6217c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:45:05 -0700 Subject: [PATCH 43/69] s3:libsmb: Plumb cli_smb2_qpathinfo2() inside cli_qpathinfo2(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 ef543e4443f8c2520cb241a27cc1a73527944317 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:46:05 -0700 Subject: [PATCH 44/69] s3:libsmb: Plumb cli_smb2_qpathinfo_streams() inside cli_qpathinfo_streams(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 54edc684c0d0647ce585274a4181846ea756ee3a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:47:21 -0700 Subject: [PATCH 45/69] s3:libsmb: Plumb cli_smb2_qfileinfo_basic() inside cli_qfileinfo_basic(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 46eaf626c3169430709f568219fc08ff6527e88c Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 10:52:02 -0700 Subject: [PATCH 46/69] s3:libsmb: Plumb cli_smb2_qpathinfo_basic() inside cli_qpathinfo_basic(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 8ac89c81996b3cab768592b925794844d7d593b1 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:50:03 -0700 Subject: [PATCH 47/69] s3:libsmb: Plumb cli_smb2_qpathinfo_alt_name() inside cli_qpathinfo_alt_name(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 7cb203031f9f6118006a3c4e6ec374924e379108 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 11:00:08 -0700 Subject: [PATCH 48/69] s3:libsmb: Plumb cli_smb2_query_security_descriptor() inside cli_query_security_descriptor(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 8ccfa82532fb007299021c3156284156de30554b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 11:00:49 -0700 Subject: [PATCH 49/69] s3:libsmb: Plumb cli_smb2_set_security_descriptor() inside cli_set_security_descriptor(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher --- 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 78bf35c8eaac20d9cd4fd111cde988f14281172a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 16:33:30 +0200 Subject: [PATCH 50/69] s3:libsmb: add SMB2 support to cli_push* Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 779638ea97b977fc52bc22e187d625ca4e0cc370 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 18:20:08 +0200 Subject: [PATCH 51/69] s3:libsmb: add SMB2 support to cli_pull* Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 3cb6037e5d66d9b563a584fc1a82f865ffc3036a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 18:38:57 +0200 Subject: [PATCH 52/69] s3:libsmb: add support for SMB2 in cli_writeall() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 b12d419d57477f5dc71815e1e5a6ac9ae9fb2d44 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 11:38:22 +0200 Subject: [PATCH 53/69] s3:libsmb: make cli_tdis_send/recv static Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 eb45de970e9fad4f437fab9b4890cba1b7bfd4d2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 11:44:10 +0200 Subject: [PATCH 54/69] 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 --- 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 68c9c839d1453bfbec221dcbe6a832c9377f74a1 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 11:44:58 +0200 Subject: [PATCH 55/69] s3:libsmb: call smb2cli_tdis() from cli_tdis() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 f117ffd74860f3bae40ec18d402e0a35dabdf05c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 11:48:40 +0200 Subject: [PATCH 56/69] s3:libsmb: make cli_ulogoff_send/recv static Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 2b49e1943dfdaa1ee91104bb36f09f2bfe1cfd24 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 15:18:47 -0700 Subject: [PATCH 57/69] s3:libsmb: call smb2cli_logoff() from cli_ulogoff() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison --- 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 b873e4cb0ecd96c00484eb54c5d2460053f388a6 Mon Sep 17 00:00:00 2001 From: Volker Lendecke Date: Mon, 19 Aug 2013 22:36:02 +0200 Subject: [PATCH 58/69] 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 --- 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 aba2cdbad6fef1aad7e07fdadab86c7f84a3a25b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 11:45:43 -0700 Subject: [PATCH 59/69] Remove restrictions on setting iosize inside smbclient for SMB2 connections. Signed-off-by: Jeremy Allison --- 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 fb483d9c00e28fc9e7b441269170be2ee950f6f6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 10:44:34 -0700 Subject: [PATCH 60/69] As SMB3 has transport level encryption, allow smbclient -e to force encryted SMB3 transport. Signed-off-by: Jeremy Allison --- 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 0d6ef86969e90134a712220dd2692d233481c15a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 13:49:39 -0700 Subject: [PATCH 61/69] 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 --- 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 99d8f935c3bfedebd8b0575277c896723434c4e8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:44:14 -0700 Subject: [PATCH 62/69] Add "max protocol" command line documentation for smbcacls. Signed-off-by: Jeremy Allison --- 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 6a73b249761366de14ef73887e3df42599457622 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:45:26 -0700 Subject: [PATCH 63/69] Add "-e" encrypt transport command line option documentation for smbcacls. Signed-off-by: Jeremy Allison --- 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 7507ae0e73daefa2ccff5a8c33c3ea6a0fe6f0a7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:47:13 -0700 Subject: [PATCH 64/69] Expand on the documentation of -m max-protocol for SMB2/3 for smbclient. Signed-off-by: Jeremy Allison --- 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 5f10e494323145b97e5d484fe0a4156b48f11a86 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:48:18 -0700 Subject: [PATCH 65/69] Fix the documentation for --send-buffersize for the new default value of zero for smbclient. Signed-off-by: Jeremy Allison --- 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 f85527cd0e71b95f69bffb3e6473d9b3eac498e7 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:49:41 -0700 Subject: [PATCH 66/69] Fix the documentation of the iosize command to explain the new zero default for smbclient. Signed-off-by: Jeremy Allison --- 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 086bc7ffc636f52bbf650d41c1ed0142423f3eca Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:53:45 -0700 Subject: [PATCH 67/69] Fix the documentation of --encrypt to explain SMB3 encryption for smbclient. Signed-off-by: Jeremy Allison --- 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 a1830c2e75f31047c93f26c71ec55c0aa19e0c64 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:56:22 -0700 Subject: [PATCH 68/69] Add documentation for the new -t parameter in smbclient. Signed-off-by: Jeremy Allison --- 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 3faaf7d720f5ba38ef7a0a5f532f1c03ef0fb3bc Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 16 Aug 2013 16:57:34 -0700 Subject: [PATCH 69/69] Add documentation for the new internal command timeout to smbclient. Signed-off-by: Jeremy Allison --- 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