From 71c9021747cf111d55b1b919c65397f75e81e1f6 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 15:17:01 -0700 Subject: [PATCH 01/57] s3:param: Correctly set up cli_maxprotocol, cli_minprotocol in our parameter block. Set to PROTOCOL_NT1, PROTOCOL_CORE by default. Bug: https://bugzilla.samba.org/show_bug.cgi?id=9829 Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit f2fb829cee81996c62ff91cb8d1e9997008ffb42) --- source3/include/proto.h | 2 ++ source3/param/loadparm.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/source3/include/proto.h b/source3/include/proto.h index a9270fc..e3d2006 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -1190,6 +1190,8 @@ int lp_deadtime(void); bool lp_getwd_cache(void); int lp_srv_maxprotocol(void); int lp_srv_minprotocol(void); +int lp_cli_maxprotocol(void); +int lp_cli_minprotocol(void); int lp_security(void); int lp__server_role(void); int lp__security(void); diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c index fa2f9b6..229ebd8 100644 --- a/source3/param/loadparm.c +++ b/source3/param/loadparm.c @@ -828,6 +828,8 @@ static void init_globals(bool reinit_globals) Globals.open_files_db_hash_size = SMB_OPEN_DATABASE_TDB_HASH_SIZE; Globals.srv_maxprotocol = PROTOCOL_SMB3_00; Globals.srv_minprotocol = PROTOCOL_LANMAN1; + Globals.cli_maxprotocol = PROTOCOL_NT1; + Globals.cli_minprotocol = PROTOCOL_CORE; Globals.security = SEC_USER; Globals.bEncryptPasswords = true; Globals.clientSchannel = Auto; -- 1.7.9.5 From f192428849e67a71b4d2c76d101b54fff5cdb49a Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:08:49 +0200 Subject: [PATCH 02/57] s3:client: avoid interpret_protocol() lp_set_cmdline("client max protocol",...) and lp_cli_maxprotocol() are the more generic solution. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 861ee9319f3cce8f104fd30c7139323ac3d3319d) --- source3/client/client.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source3/client/client.c b/source3/client/client.c index d03d1a4..d09d012 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -58,7 +58,7 @@ const char *cmd_ptr = NULL; static int io_bufsize = 524288; static int name_type = 0x20; -static int max_protocol = PROTOCOL_NT1; +static int max_protocol = -1; static int process_tok(char *tok); static int cmd_help(void); @@ -5456,7 +5456,7 @@ static int do_message_op(struct user_auth_info *a_info) } break; case 'm': - max_protocol = interpret_protocol(poptGetOptArg(pc), max_protocol); + lp_set_cmdline("client max protocol", poptGetOptArg(pc)); break; case 'T': /* We must use old option processing for this. Find the @@ -5574,6 +5574,8 @@ static int do_message_op(struct user_auth_info *a_info) /* Ensure we have a password (or equivalent). */ set_cmdline_auth_info_getpass(auth_info); + max_protocol = lp_cli_maxprotocol(); + if (tar_type) { if (cmdstr) process_command_string(cmdstr); -- 1.7.9.5 From 75c3c045a1658d105fcca5eff77125b5d5eaf3e6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:10:13 +0200 Subject: [PATCH 03/57] s3:torture: avoid interpret_protocol() lp_set_cmdline("client max protocol",...) and lp_cli_maxprotocol() are the more generic solution. https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 2c3c8caa0cc7b085231b2edc100ce2332e1e0085) --- source3/torture/masktest.c | 5 +++-- source3/torture/torture.c | 3 +-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/source3/torture/masktest.c b/source3/torture/masktest.c index 8332e80..bca35aa 100644 --- a/source3/torture/masktest.c +++ b/source3/torture/masktest.c @@ -27,7 +27,7 @@ static fstring password; static fstring username; static int got_pass; -static int max_protocol = PROTOCOL_NT1; +static int max_protocol = -1; static bool showall = False; static bool old_list = False; static const char *maskchars = "<>\"?*abc."; @@ -510,7 +510,7 @@ static void usage(void) verbose++; break; case 'M': - max_protocol = interpret_protocol(optarg, max_protocol); + lp_set_cmdline("client max protocol", optarg); break; case 'U': fstrcpy(username,optarg); @@ -548,6 +548,7 @@ static void usage(void) argc -= optind; argv += optind; + max_protocol = lp_cli_maxprotocol(); cli = connect_one(share); if (!cli) { diff --git a/source3/torture/torture.c b/source3/torture/torture.c index 3c6db30..c6c5322 100644 --- a/source3/torture/torture.c +++ b/source3/torture/torture.c @@ -46,7 +46,6 @@ extern char *optarg; extern int optind; fstring host, workgroup, share, password, username, myname; -static int max_protocol = PROTOCOL_NT1; static const char *sockops="TCP_NODELAY"; int torture_nprocs=1; static int port_to_use=0; @@ -9713,7 +9712,7 @@ static void usage(void) fstrcpy(workgroup,optarg); break; case 'm': - max_protocol = interpret_protocol(optarg, max_protocol); + lp_set_cmdline("client max protocol", optarg); break; case 'N': torture_nprocs = atoi(optarg); -- 1.7.9.5 From ceb1d91a273e820c6657556d6323e98d8f101451 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:11:41 +0200 Subject: [PATCH 04/57] s3:lib: remove unused interpret_protocol() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 9188ee4ab195a18b1bd697bced8613f98a6a91d9) --- source3/include/proto.h | 1 - source3/lib/util.c | 25 ------------------------- 2 files changed, 26 deletions(-) diff --git a/source3/include/proto.h b/source3/include/proto.h index e3d2006..493d1da 100644 --- a/source3/include/proto.h +++ b/source3/include/proto.h @@ -401,7 +401,6 @@ void add_to_large_array(TALLOC_CTX *mem_ctx, size_t element_size, ssize_t *array_size); char *get_myname(TALLOC_CTX *ctx); char *get_mydnsdomname(TALLOC_CTX *ctx); -int interpret_protocol(const char *str,int def); char *automount_lookup(TALLOC_CTX *ctx, const char *user_name); char *automount_lookup(TALLOC_CTX *ctx, const char *user_name); bool process_exists(const struct server_id pid); diff --git a/source3/lib/util.c b/source3/lib/util.c index 93aab3c..bf6c8c5 100644 --- a/source3/lib/util.c +++ b/source3/lib/util.c @@ -559,31 +559,6 @@ char *get_mydnsdomname(TALLOC_CTX *ctx) } } -/**************************************************************************** - Interpret a protocol description string, with a default. -****************************************************************************/ - -int interpret_protocol(const char *str,int def) -{ - if (strequal(str,"NT1")) - return(PROTOCOL_NT1); - if (strequal(str,"LANMAN2")) - return(PROTOCOL_LANMAN2); - if (strequal(str,"LANMAN1")) - return(PROTOCOL_LANMAN1); - if (strequal(str,"CORE")) - return(PROTOCOL_CORE); - if (strequal(str,"COREPLUS")) - return(PROTOCOL_COREPLUS); - if (strequal(str,"CORE+")) - return(PROTOCOL_COREPLUS); - - DEBUG(0,("Unrecognised protocol level %s\n",str)); - - return(def); -} - - #if (defined(HAVE_NETGROUP) && defined(WITH_AUTOMOUNT)) /****************************************************************** Remove any mount options such as -rsize=2048,wsize=2048 etc. -- 1.7.9.5 From 8d233fcb63cad58e368933b6f90a87383ee842b2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 11:35:44 -0700 Subject: [PATCH 05/57] s3:libsmb: Modify cli_start_connection_connected() to use lp_cli_minprotocol()/lp_cli_maxprotocol() instead of hard coding PROTOCOL_CORE, PROTOCOL_NT1. https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 42f510c155b98f3df5106aebd1de54d1749b9b1c) --- source3/libsmb/cliconnect.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 7179c4f..fa9d99f 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -3123,7 +3123,8 @@ static void cli_start_connection_connected(struct tevent_req *subreq) subreq = smbXcli_negprot_send(state, state->ev, state->cli->conn, state->cli->timeout, - PROTOCOL_CORE, PROTOCOL_NT1); + lp_cli_minprotocol(), + lp_cli_maxprotocol()); if (tevent_req_nomem(subreq, req)) { return; } -- 1.7.9.5 From 87d8832eabac562d748f5a1b44de9fbe5fd6f059 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 9 Aug 2013 11:15:48 -0700 Subject: [PATCH 06/57] s3:libsmb: Ensure we ask for DEFAULT_SMB2_MAX_CREDITS on successful negprot. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 14421323d1dd3744cb8553f0e6a5a7436554bf2d) --- source3/libsmb/cliconnect.c | 10 ++++++++++ source3/libsmb/clidfs.c | 5 +++++ 2 files changed, 15 insertions(+) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index fa9d99f..d74ea0e 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -3135,6 +3135,8 @@ static void cli_start_connection_done(struct tevent_req *subreq) { struct tevent_req *req = tevent_req_callback_data( subreq, struct tevent_req); + struct cli_start_connection_state *state = tevent_req_data( + req, struct cli_start_connection_state); NTSTATUS status; status = smbXcli_negprot_recv(subreq); @@ -3142,6 +3144,13 @@ static void cli_start_connection_done(struct tevent_req *subreq) if (tevent_req_nterror(req, status)) { return; } + + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + /* Ensure we ask for some initial credits. */ + smb2cli_conn_set_max_credits(state->cli->conn, + DEFAULT_SMB2_MAX_CREDITS); + } + tevent_req_done(req); } @@ -3156,6 +3165,7 @@ static NTSTATUS cli_start_connection_recv(struct tevent_req *req, return status; } *output_cli = state->cli; + return NT_STATUS_OK; } diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c index 95f8817..1ed6ac5 100644 --- a/source3/libsmb/clidfs.c +++ b/source3/libsmb/clidfs.c @@ -160,6 +160,11 @@ static NTSTATUS do_connect(TALLOC_CTX *ctx, return status; } + if (smbXcli_conn_protocol(c->conn) >= PROTOCOL_SMB2_02) { + /* Ensure we ask for some initial credits. */ + smb2cli_conn_set_max_credits(c->conn, DEFAULT_SMB2_MAX_CREDITS); + } + username = get_cmdline_auth_info_username(auth_info); password = get_cmdline_auth_info_password(auth_info); -- 1.7.9.5 From f43056ba600325786b7a8b0d51a2a65d6b1bd766 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:46:34 +0200 Subject: [PATCH 07/57] s3:lib/netapi: make use of lp_cli_maxprotocol() https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 7e455e9ed2b298df6b735a89abdd75564375ef34) --- source3/lib/netapi/cm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/lib/netapi/cm.c b/source3/lib/netapi/cm.c index 36e8731..da3d2e1 100644 --- a/source3/lib/netapi/cm.c +++ b/source3/lib/netapi/cm.c @@ -111,7 +111,7 @@ static WERROR libnetapi_open_ipc_connection(struct libnetapi_ctx *ctx, server_name, "IPC$", auth_info, false, false, - PROTOCOL_NT1, + lp_cli_maxprotocol(), 0, 0x20, &cli_ipc); if (NT_STATUS_IS_OK(status)) { cli_set_username(cli_ipc, ctx->username); -- 1.7.9.5 From 355fdb2c83d041cabc29873bee3001db43c0aae6 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 13:48:31 +0200 Subject: [PATCH 08/57] s3:winbindd: make use of lp_cli_{min,max}protocol() This changes winbindd back to use NT1 as defeault. https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit dd9155a7ec7f1989cb18e79907d0fa1c9ee845a4) --- source3/winbindd/winbindd_cm.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/source3/winbindd/winbindd_cm.c b/source3/winbindd/winbindd_cm.c index 48322cb..85139d0 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.7.9.5 From 364809db913fc7da3b19794153d3c2797788c210 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 14:00:45 +0200 Subject: [PATCH 09/57] s3:libsmb: use lp_cli_minprotocol() in do_connect() https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 42a493dff0e4ade04b6e94caf0b7ae14b6cf60eb) --- source3/libsmb/clidfs.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clidfs.c b/source3/libsmb/clidfs.c index 1ed6ac5..1d92843 100644 --- a/source3/libsmb/clidfs.c +++ b/source3/libsmb/clidfs.c @@ -150,7 +150,8 @@ static NTSTATUS do_connect(TALLOC_CTX *ctx, } DEBUG(4,(" session request ok\n")); - status = smbXcli_negprot(c->conn, c->timeout, PROTOCOL_CORE, + status = smbXcli_negprot(c->conn, c->timeout, + lp_cli_minprotocol(), max_protocol); if (!NT_STATUS_IS_OK(status)) { -- 1.7.9.5 From 3dbf95925cb561f5c794cfd733f9dfd6a1710bae Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Sun, 11 Aug 2013 14:01:36 +0200 Subject: [PATCH 10/57] s3:libsmb: make use of lp_cli_{min,max}protocol() in SMBC_server_internal() https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit daeb0bdfc49ace6151bbca34cbbf55486d66abb6) --- source3/libsmb/libsmb_server.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/source3/libsmb/libsmb_server.c b/source3/libsmb/libsmb_server.c index fc3977e..7a20c30 100644 --- a/source3/libsmb/libsmb_server.c +++ b/source3/libsmb/libsmb_server.c @@ -449,9 +449,9 @@ SMBC_server_internal(TALLOC_CTX *ctx, cli_set_timeout(c, smbc_getTimeout(context)); - status = smbXcli_negprot(c->conn, c->timeout, PROTOCOL_CORE, - PROTOCOL_NT1); - + status = smbXcli_negprot(c->conn, c->timeout, + lp_cli_minprotocol(), + lp_cli_maxprotocol()); if (!NT_STATUS_IS_OK(status)) { cli_shutdown(c); errno = ETIMEDOUT; -- 1.7.9.5 From da5c0d40de6bfb26f3dfbce3d7d5011bd676b6b2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 11:43:16 -0700 Subject: [PATCH 11/57] s3:smbcacls: Add -m option to smbcacls. https://bugzilla.samba.org/show_bug.cgi?id=9514 Signed-off-by: Jeremy Allison Signed-off-by: Stefan Metzmacher Reviewed-by: Stefan Metzmacher (cherry picked from commit f6ce50a8aca9eb024af4eb5e3dd620fe5e04e913) --- source3/utils/smbcacls.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c index 39400c8..3ee7034 100644 --- a/source3/utils/smbcacls.c +++ b/source3/utils/smbcacls.c @@ -1386,6 +1386,7 @@ static struct cli_state *connect_one(struct user_auth_info *auth_info, }, { "test-args", 't', POPT_ARG_NONE, &test_args, 1, "Test arguments"}, { "domain-sid", 0, POPT_ARG_STRING, &domain_sid, 0, "Domain SID for sddl", "SID"}, + { "max-protocol", 'm', POPT_ARG_STRING, NULL, 'm', "Set the max protocol level", "LEVEL" }, POPT_COMMON_SAMBA POPT_COMMON_CONNECTION POPT_COMMON_CREDENTIALS @@ -1456,6 +1457,9 @@ static struct cli_state *connect_one(struct user_auth_info *auth_info, owner_username = poptGetOptArg(pc); change_mode = REQUEST_INHERIT; break; + case 'm': + lp_set_cmdline("client max protocol", poptGetOptArg(pc)); + break; } } -- 1.7.9.5 From ba687032e530ecc55a845f12faa2b6bfe6a5a4c2 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 08:12:08 +0200 Subject: [PATCH 12/57] libcli/smb: fix the credit handling on a SMB1 => SMB2 negotiate Our cur_credit value had 1 credit too many in the case of an SMB1 => SMB2 upgrade. When we max out the credits the server disconnected the connection. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 97288b7f1048c1bf712463293a1e62737738292c) --- libcli/smb/smbXcli_base.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 5a5828a..b950900 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -4404,9 +4404,14 @@ static NTSTATUS smbXcli_negprot_dispatch_incoming(struct smbXcli_conn *conn, /* * we got an SMB2 answer, which consumed sequence number 0 - * so we need to use 1 as the next one + * so we need to use 1 as the next one. + * + * we also need to set the current credits to 0 + * as we consumed the initial one. The SMB2 answer + * hopefully grant us a new credit. */ conn->smb2.mid = 1; + conn->smb2.cur_credits = 0; tevent_req_set_callback(subreq, smbXcli_negprot_smb2_done, req); conn->dispatch_incoming = smb2cli_conn_dispatch_incoming; return smb2cli_conn_dispatch_incoming(conn, tmp_mem, inbuf); -- 1.7.9.5 From dfd3b4d836f692b5e9906f5c5f7dfa495090a4dd Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 14:41:24 -0700 Subject: [PATCH 13/57] libcli/smb: Fix smb2cli_write_recv() and smb2cli_write() to return the bytes written. Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 00f784ec91d2cfa95b20327ac20f5bc3fa1f400e) --- libcli/smb/smb2cli_write.c | 30 +++++++++++++++++++++++++----- libcli/smb/smbXcli_base.h | 6 ++++-- source3/libsmb/cli_np_tstream.c | 7 +++++-- source3/torture/test_smb2.c | 14 +++++++------- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/libcli/smb/smb2cli_write.c b/libcli/smb/smb2cli_write.c index 8e65460..89137bd 100644 --- a/libcli/smb/smb2cli_write.c +++ b/libcli/smb/smb2cli_write.c @@ -26,6 +26,7 @@ struct smb2cli_write_state { uint8_t fixed[48]; uint8_t dyn_pad[1]; + uint32_t written; }; static void smb2cli_write_done(struct tevent_req *subreq); @@ -94,7 +95,11 @@ static void smb2cli_write_done(struct tevent_req *subreq) struct tevent_req *req = tevent_req_callback_data(subreq, struct tevent_req); + struct smb2cli_write_state *state = + tevent_req_data(req, + struct smb2cli_write_state); NTSTATUS status; + struct iovec *iov; static const struct smb2cli_req_expected_response expected[] = { { .status = NT_STATUS_OK, @@ -102,18 +107,32 @@ static void smb2cli_write_done(struct tevent_req *subreq) } }; - status = smb2cli_req_recv(subreq, NULL, NULL, + status = smb2cli_req_recv(subreq, state, &iov, expected, ARRAY_SIZE(expected)); TALLOC_FREE(subreq); if (tevent_req_nterror(req, status)) { return; } + state->written = IVAL(iov[1].iov_base, 4); tevent_req_done(req); } -NTSTATUS smb2cli_write_recv(struct tevent_req *req) +NTSTATUS smb2cli_write_recv(struct tevent_req *req, uint32_t *written) { - return tevent_req_simple_recv_ntstatus(req); + struct smb2cli_write_state *state = + tevent_req_data(req, + struct smb2cli_write_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + if (written) { + *written = state->written; + } + tevent_req_received(req); + return NT_STATUS_OK; } NTSTATUS smb2cli_write(struct smbXcli_conn *conn, @@ -126,7 +145,8 @@ NTSTATUS smb2cli_write(struct smbXcli_conn *conn, uint64_t fid_volatile, uint32_t remaining_bytes, uint32_t flags, - const uint8_t *data) + const uint8_t *data, + uint32_t *written) { TALLOC_CTX *frame = talloc_stackframe(); struct tevent_context *ev; @@ -155,7 +175,7 @@ NTSTATUS smb2cli_write(struct smbXcli_conn *conn, if (!tevent_req_poll_ntstatus(req, ev, &status)) { goto fail; } - status = smb2cli_write_recv(req); + status = smb2cli_write_recv(req, written); fail: TALLOC_FREE(frame); return status; diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index f7b60d3..997869b 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -429,7 +429,8 @@ struct tevent_req *smb2cli_write_send(TALLOC_CTX *mem_ctx, uint32_t remaining_bytes, uint32_t flags, const uint8_t *data); -NTSTATUS smb2cli_write_recv(struct tevent_req *req); +NTSTATUS smb2cli_write_recv(struct tevent_req *req, + uint32_t *written); NTSTATUS smb2cli_write(struct smbXcli_conn *conn, uint32_t timeout_msec, struct smbXcli_session *session, @@ -440,7 +441,8 @@ NTSTATUS smb2cli_write(struct smbXcli_conn *conn, uint64_t fid_volatile, uint32_t remaining_bytes, uint32_t flags, - const uint8_t *data); + const uint8_t *data, + uint32_t *written); struct tevent_req *smb2cli_flush_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, diff --git a/source3/libsmb/cli_np_tstream.c b/source3/libsmb/cli_np_tstream.c index c7ec664..07835a5 100644 --- a/source3/libsmb/cli_np_tstream.c +++ b/source3/libsmb/cli_np_tstream.c @@ -527,8 +527,11 @@ static void tstream_cli_np_writev_write_done(struct tevent_req *subreq) if (cli_nps->is_smb1) { status = cli_write_andx_recv(subreq, &written); } else { - status = smb2cli_write_recv(subreq); - written = cli_nps->write.ofs; // TODO: get the value from the server + uint32_t smb2_written; + status = smb2cli_write_recv(subreq, &smb2_written); + if (NT_STATUS_IS_OK(status)) { + written = smb2_written; + } } TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { diff --git a/source3/torture/test_smb2.c b/source3/torture/test_smb2.c index ec695da..7ca9f49 100644 --- a/source3/torture/test_smb2.c +++ b/source3/torture/test_smb2.c @@ -91,7 +91,7 @@ bool run_smb2_basic(int dummy) status = smb2cli_write(cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_write returned %s\n", nt_errstr(status)); return false; @@ -349,7 +349,7 @@ bool run_smb2_session_reconnect(int dummy) status = smb2cli_write(cli1->conn, cli1->timeout, cli1->smb2.session, cli1->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_write returned %s\n", nt_errstr(status)); return false; @@ -545,7 +545,7 @@ bool run_smb2_session_reconnect(int dummy) status = smb2cli_write(cli2->conn, cli2->timeout, cli2->smb2.session, cli2->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) && !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) { @@ -605,7 +605,7 @@ bool run_smb2_session_reconnect(int dummy) status = smb2cli_write(cli2->conn, cli2->timeout, cli2->smb2.session, cli1->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_FILE_CLOSED) && !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) { @@ -670,7 +670,7 @@ bool run_smb2_session_reconnect(int dummy) status = smb2cli_write(cli2->conn, cli2->timeout, cli2->smb2.session, cli2->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_write returned %s\n", nt_errstr(status)); return false; @@ -765,7 +765,7 @@ bool run_smb2_tcon_dependence(int dummy) status = smb2cli_write(cli->conn, cli->timeout, cli->smb2.session, cli->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_write returned %s\n", nt_errstr(status)); return false; @@ -1172,7 +1172,7 @@ bool run_smb2_multi_channel(int dummy) status = smb2cli_write(cli1->conn, cli1->timeout, cli1->smb2.session, cli1->smb2.tcon, strlen(hello), 0, fid_persistent, - fid_volatile, 0, 0, (const uint8_t *)hello); + fid_volatile, 0, 0, (const uint8_t *)hello, NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_write returned %s\n", nt_errstr(status)); return false; -- 1.7.9.5 From 002cbda4cfdb912d819a1a3f052df124df34e0af Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 15:01:50 -0700 Subject: [PATCH 14/57] libcli/smb: Change smb2cli_create() and smb2cli_create_recv() to return a parameter blob of the newly opened/created file. Will use in the smb2 client code. Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 1229881df6bd22d4b5055ad283061332ba1c9bc8) --- libcli/smb/smb2_create_blob.h | 12 ++++++++++ libcli/smb/smb2cli_create.c | 39 +++++++++++++++---------------- libcli/smb/smbXcli_base.h | 7 ++++-- source3/libsmb/cli_np_tstream.c | 3 ++- source3/torture/test_smb2.c | 48 ++++++++++++++++++++++++++------------- 5 files changed, 69 insertions(+), 40 deletions(-) diff --git a/libcli/smb/smb2_create_blob.h b/libcli/smb/smb2_create_blob.h index 008befe..2f915b3 100644 --- a/libcli/smb/smb2_create_blob.h +++ b/libcli/smb/smb2_create_blob.h @@ -33,6 +33,18 @@ struct smb2_create_blobs { struct smb2_create_blob *blobs; }; +struct smb2_create_returns { + uint8_t oplock_level; + uint32_t create_action; + NTTIME creation_time; + NTTIME last_access_time; + NTTIME last_write_time; + NTTIME change_time; + uint64_t allocation_size; + uint64_t end_of_file; + uint32_t file_attributes; +}; + /* parse a set of SMB2 create blobs */ diff --git a/libcli/smb/smb2cli_create.c b/libcli/smb/smb2cli_create.c index 627bdcb..020a468 100644 --- a/libcli/smb/smb2cli_create.c +++ b/libcli/smb/smb2cli_create.c @@ -27,17 +27,9 @@ struct smb2cli_create_state { uint8_t fixed[56]; - uint8_t oplock_level; - uint32_t create_action; - NTTIME creation_time; - NTTIME last_access_time; - NTTIME last_write_time; - NTTIME change_time; - uint64_t allocation_size; - uint64_t end_of_file; - uint32_t file_attributes; uint64_t fid_persistent; uint64_t fid_volatile; + struct smb2_create_returns cr; struct smb2_create_blobs blobs; }; @@ -179,15 +171,15 @@ static void smb2cli_create_done(struct tevent_req *subreq) body = (uint8_t *)iov[1].iov_base; - state->oplock_level = CVAL(body, 2); - state->create_action = IVAL(body, 4); - state->creation_time = BVAL(body, 8); - state->last_access_time = BVAL(body, 16); - state->last_write_time = BVAL(body, 24); - state->change_time = BVAL(body, 32); - state->allocation_size = BVAL(body, 40); - state->end_of_file = BVAL(body, 48); - state->file_attributes = IVAL(body, 56); + state->cr.oplock_level = CVAL(body, 2); + state->cr.create_action = IVAL(body, 4); + state->cr.creation_time = BVAL(body, 8); + state->cr.last_access_time = BVAL(body, 16); + state->cr.last_write_time = BVAL(body, 24); + state->cr.change_time = BVAL(body, 32); + state->cr.allocation_size = BVAL(body, 40); + state->cr.end_of_file = BVAL(body, 48); + state->cr.file_attributes = IVAL(body, 56); state->fid_persistent = BVAL(body, 64); state->fid_volatile = BVAL(body, 72); @@ -213,7 +205,8 @@ static void smb2cli_create_done(struct tevent_req *subreq) NTSTATUS smb2cli_create_recv(struct tevent_req *req, uint64_t *fid_persistent, - uint64_t *fid_volatile) + uint64_t *fid_volatile, + struct smb2_create_returns *cr) { struct smb2cli_create_state *state = tevent_req_data(req, @@ -225,6 +218,9 @@ NTSTATUS smb2cli_create_recv(struct tevent_req *req, } *fid_persistent = state->fid_persistent; *fid_volatile = state->fid_volatile; + if (cr) { + *cr = state->cr; + } return NT_STATUS_OK; } @@ -242,7 +238,8 @@ NTSTATUS smb2cli_create(struct smbXcli_conn *conn, uint32_t create_options, struct smb2_create_blobs *blobs, uint64_t *fid_persistent, - uint64_t *fid_volatile) + uint64_t *fid_volatile, + struct smb2_create_returns *cr) { TALLOC_CTX *frame = talloc_stackframe(); struct tevent_context *ev; @@ -273,7 +270,7 @@ NTSTATUS smb2cli_create(struct smbXcli_conn *conn, if (!tevent_req_poll_ntstatus(req, ev, &status)) { goto fail; } - status = smb2cli_create_recv(req, fid_persistent, fid_volatile); + status = smb2cli_create_recv(req, fid_persistent, fid_volatile, cr); fail: TALLOC_FREE(frame); return status; diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index 997869b..a497e13 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -28,6 +28,7 @@ struct smb_trans_enc_state; struct GUID; struct iovec; struct smb2_create_blobs; +struct smb2_create_returns; struct smbXcli_conn *smbXcli_conn_create(TALLOC_CTX *mem_ctx, int fd, @@ -353,7 +354,8 @@ struct tevent_req *smb2cli_create_send( struct smb2_create_blobs *blobs); NTSTATUS smb2cli_create_recv(struct tevent_req *req, uint64_t *fid_persistent, - uint64_t *fid_volatile); + uint64_t *fid_volatile, + struct smb2_create_returns *cr); NTSTATUS smb2cli_create(struct smbXcli_conn *conn, uint32_t timeout_msec, struct smbXcli_session *session, @@ -368,7 +370,8 @@ NTSTATUS smb2cli_create(struct smbXcli_conn *conn, uint32_t create_options, struct smb2_create_blobs *blobs, uint64_t *fid_persistent, - uint64_t *fid_volatile); + uint64_t *fid_volatile, + struct smb2_create_returns *cr); struct tevent_req *smb2cli_close_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, diff --git a/source3/libsmb/cli_np_tstream.c b/source3/libsmb/cli_np_tstream.c index 07835a5..f3a9962 100644 --- a/source3/libsmb/cli_np_tstream.c +++ b/source3/libsmb/cli_np_tstream.c @@ -208,7 +208,8 @@ static void tstream_cli_np_open_done(struct tevent_req *subreq) } else { status = smb2cli_create_recv(subreq, &state->fid_persistent, - &state->fid_volatile); + &state->fid_volatile, + NULL); } TALLOC_FREE(subreq); if (!NT_STATUS_IS_OK(status)) { diff --git a/source3/torture/test_smb2.c b/source3/torture/test_smb2.c index 7ca9f49..3bcd2ed 100644 --- a/source3/torture/test_smb2.c +++ b/source3/torture/test_smb2.c @@ -83,7 +83,8 @@ bool run_smb2_basic(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create returned %s\n", nt_errstr(status)); return false; @@ -145,7 +146,8 @@ bool run_smb2_basic(int dummy) FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create returned %s\n", nt_errstr(status)); return false; @@ -341,7 +343,8 @@ bool run_smb2_session_reconnect(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create on cli1 %s\n", nt_errstr(status)); return false; @@ -575,7 +578,8 @@ bool run_smb2_session_reconnect(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) && !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) { printf("smb2cli_create on cli2 %s\n", nt_errstr(status)); @@ -635,7 +639,8 @@ bool run_smb2_session_reconnect(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED) && !NT_STATUS_EQUAL(status, NT_STATUS_NETWORK_NAME_DELETED)) { @@ -662,7 +667,8 @@ bool run_smb2_session_reconnect(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create on cli2 %s\n", nt_errstr(status)); return false; @@ -757,7 +763,8 @@ bool run_smb2_tcon_dependence(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create on cli %s\n", nt_errstr(status)); return false; @@ -1164,7 +1171,8 @@ bool run_smb2_multi_channel(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create on cli2 %s\n", nt_errstr(status)); return false; @@ -1324,7 +1332,8 @@ bool run_smb2_multi_channel(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { printf("smb2cli_create %s\n", nt_errstr(status)); return false; @@ -1341,7 +1350,8 @@ bool run_smb2_multi_channel(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { printf("smb2cli_create %s\n", nt_errstr(status)); return false; @@ -1358,7 +1368,8 @@ bool run_smb2_multi_channel(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { printf("smb2cli_create %s\n", nt_errstr(status)); return false; @@ -1489,7 +1500,8 @@ bool run_smb2_session_reauth(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create %s\n", nt_errstr(status)); return false; @@ -1508,7 +1520,8 @@ bool run_smb2_session_reauth(int dummy) FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &dir_persistent, - &dir_volatile); + &dir_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create returned %s\n", nt_errstr(status)); return false; @@ -1691,7 +1704,8 @@ bool run_smb2_session_reauth(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { printf("smb2cli_create %s\n", nt_errstr(status)); return false; @@ -1710,7 +1724,8 @@ bool run_smb2_session_reauth(int dummy) FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &dir_persistent, - &dir_volatile); + &dir_volatile, + NULL); if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) { printf("smb2cli_create returned %s\n", nt_errstr(status)); return false; @@ -1865,7 +1880,8 @@ bool run_smb2_session_reauth(int dummy) FILE_DELETE_ON_CLOSE, /* create_options, */ NULL, /* smb2_create_blobs *blobs */ &fid_persistent, - &fid_volatile); + &fid_volatile, + NULL); if (!NT_STATUS_IS_OK(status)) { printf("smb2cli_create %s\n", nt_errstr(status)); return false; -- 1.7.9.5 From 00346dc14e5ade6c25e01ea31d7c811dc7ba0abf Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 09:50:29 +0200 Subject: [PATCH 15/57] libcli/smb: calculate the credit charge on the input and output dyn_len Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 318735fd5e15c5fd7010c0f657c86d27b45279ac) --- libcli/smb/smbXcli_base.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index b950900..ef9d82a 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -246,6 +246,11 @@ struct smbXcli_req_state { */ struct iovec *recv_iov; + /* + * the expected max for the response dyn_len + */ + uint32_t max_dyn_len; + uint16_t credit_charge; bool should_sign; @@ -2787,7 +2792,12 @@ NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs, } if (state->conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) { - charge = (MAX(state->smb2.dyn_len, 1) - 1)/ 65536 + 1; + uint32_t max_dyn_len = 1; + + max_dyn_len = MAX(max_dyn_len, state->smb2.dyn_len); + max_dyn_len = MAX(max_dyn_len, state->smb2.max_dyn_len); + + charge = (max_dyn_len - 1)/ 65536 + 1; } else { charge = 1; } -- 1.7.9.5 From d8a1d009fa7dbe7e1d3b12a17c3542c16c9a673d Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 09:54:42 +0200 Subject: [PATCH 16/57] libcli/smb: pass max_dyn_len to smb2cli_req_create() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 4a3352020db962ef40728d8a754da8a9418ca8a7) --- libcli/smb/smbXcli_base.c | 11 ++++++++--- libcli/smb/smbXcli_base.h | 3 ++- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index ef9d82a..60c1c9f 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -2494,7 +2494,7 @@ static bool smb2cli_req_cancel(struct tevent_req *req) 0, /* timeout */ tcon, session, fixed, fixed_len, - NULL, 0); + NULL, 0, 0); if (subreq == NULL) { return false; } @@ -2543,7 +2543,8 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx, const uint8_t *fixed, uint16_t fixed_len, const uint8_t *dyn, - uint32_t dyn_len) + uint32_t dyn_len, + uint32_t max_dyn_len) { struct tevent_req *req; struct smbXcli_req_state *state; @@ -2616,6 +2617,7 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx, state->smb2.fixed_len = fixed_len; state->smb2.dyn = dyn; state->smb2.dyn_len = dyn_len; + state->smb2.max_dyn_len = max_dyn_len; if (state->smb2.should_encrypt) { SIVAL(state->smb2.transform, SMB2_TF_PROTOCOL_ID, SMB2_TF_MAGIC); @@ -2985,12 +2987,15 @@ struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx, { struct tevent_req *req; NTSTATUS status; + uint32_t max_dyn_len = 0; req = smb2cli_req_create(mem_ctx, ev, conn, cmd, additional_flags, clear_flags, timeout_msec, tcon, session, - fixed, fixed_len, dyn, dyn_len); + fixed, fixed_len, + dyn, dyn_len, + max_dyn_len); if (req == NULL) { return NULL; } diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index a497e13..017c0f0 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -218,7 +218,8 @@ struct tevent_req *smb2cli_req_create(TALLOC_CTX *mem_ctx, const uint8_t *fixed, uint16_t fixed_len, const uint8_t *dyn, - uint32_t dyn_len); + uint32_t dyn_len, + uint32_t max_dyn_len); void smb2cli_req_set_notify_async(struct tevent_req *req); NTSTATUS smb2cli_req_compound_submit(struct tevent_req **reqs, int num_reqs); -- 1.7.9.5 From 78b6029c63cc31dcbcdb81226225f9ba1d56bd15 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 10:25:52 +0200 Subject: [PATCH 17/57] libcli/smb: pass max_dyn_len to smb2cli_req_send() This way we can calculate the correct credit charge for requests with large output buffers. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 44b53937d59842a63e2cbfa92219f4f519530b0a) --- libcli/smb/smb2cli_close.c | 3 ++- libcli/smb/smb2cli_create.c | 13 ++++++++++++- libcli/smb/smb2cli_echo.c | 3 ++- libcli/smb/smb2cli_flush.c | 3 ++- libcli/smb/smb2cli_ioctl.c | 13 ++++++++++++- libcli/smb/smb2cli_query_directory.c | 3 ++- libcli/smb/smb2cli_query_info.c | 3 ++- libcli/smb/smb2cli_read.c | 3 ++- libcli/smb/smb2cli_session.c | 6 ++++-- libcli/smb/smb2cli_set_info.c | 3 ++- libcli/smb/smb2cli_write.c | 3 ++- libcli/smb/smbXcli_base.c | 7 ++++--- libcli/smb/smbXcli_base.h | 3 ++- source3/libsmb/smb2cli_tcon.c | 6 ++++-- source4/libcli/smb2/transport.c | 9 ++++++--- 15 files changed, 60 insertions(+), 21 deletions(-) diff --git a/libcli/smb/smb2cli_close.c b/libcli/smb/smb2cli_close.c index ed15a20..5e31056 100644 --- a/libcli/smb/smb2cli_close.c +++ b/libcli/smb/smb2cli_close.c @@ -60,7 +60,8 @@ struct tevent_req *smb2cli_close_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - NULL, 0); + NULL, 0, /* dyn* */ + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_create.c b/libcli/smb/smb2cli_create.c index 020a468..3f8d672 100644 --- a/libcli/smb/smb2cli_create.c +++ b/libcli/smb/smb2cli_create.c @@ -62,6 +62,7 @@ struct tevent_req *smb2cli_create_send( size_t blobs_offset; uint8_t *dyn; size_t dyn_len; + size_t max_dyn_len; req = tevent_req_create(mem_ctx, &state, struct smb2cli_create_state); @@ -129,13 +130,23 @@ struct tevent_req *smb2cli_create_send( data_blob_free(&blob); } + /* + * We use max_dyn_len = 0 + * as we don't explicitly ask for any output length. + * + * But it's still possible for the server to return + * large create blobs. + */ + max_dyn_len = 0; + subreq = smb2cli_req_send(state, ev, conn, SMB2_OP_CREATE, 0, 0, /* flags */ timeout_msec, tcon, session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + max_dyn_len); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_echo.c b/libcli/smb/smb2cli_echo.c index 29cbf26..39c592c 100644 --- a/libcli/smb/smb2cli_echo.c +++ b/libcli/smb/smb2cli_echo.c @@ -53,7 +53,8 @@ struct tevent_req *smb2cli_echo_send(TALLOC_CTX *mem_ctx, NULL, /* tcon */ NULL, /* session */ state->fixed, sizeof(state->fixed), - NULL, 0); + NULL, 0, /* dyn* */ + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_flush.c b/libcli/smb/smb2cli_flush.c index 0ca2699..f014720 100644 --- a/libcli/smb/smb2cli_flush.c +++ b/libcli/smb/smb2cli_flush.c @@ -58,7 +58,8 @@ struct tevent_req *smb2cli_flush_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - NULL, 0); + NULL, 0, /* dyn* */ + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_ioctl.c b/libcli/smb/smb2cli_ioctl.c index 15a990c..8de7635 100644 --- a/libcli/smb/smb2cli_ioctl.c +++ b/libcli/smb/smb2cli_ioctl.c @@ -61,6 +61,8 @@ struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx, uint32_t output_buffer_offset = 0; uint32_t output_buffer_length = 0; uint32_t pad_length = 0; + uint64_t tmp64; + uint32_t max_dyn_len = 0; req = tevent_req_create(mem_ctx, &state, struct smb2cli_ioctl_state); @@ -70,6 +72,14 @@ struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx, state->max_input_length = in_max_input_length; state->max_output_length = in_max_output_length; + tmp64 = in_max_input_length; + tmp64 += in_max_output_length; + if (tmp64 > UINT32_MAX) { + max_dyn_len = UINT32_MAX; + } else { + max_dyn_len = tmp64; + } + if (in_input_buffer) { input_buffer_offset = SMB2_HDR_BODY+0x38; input_buffer_length = in_input_buffer->length; @@ -139,7 +149,8 @@ struct tevent_req *smb2cli_ioctl_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + max_dyn_len); if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_query_directory.c b/libcli/smb/smb2cli_query_directory.c index 32f5bee..bccc529 100644 --- a/libcli/smb/smb2cli_query_directory.c +++ b/libcli/smb/smb2cli_query_directory.c @@ -93,7 +93,8 @@ struct tevent_req *smb2cli_query_directory_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + outbuf_len); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_query_info.c b/libcli/smb/smb2cli_query_info.c index 9ec16b5..454f25a 100644 --- a/libcli/smb/smb2cli_query_info.c +++ b/libcli/smb/smb2cli_query_info.c @@ -96,7 +96,8 @@ struct tevent_req *smb2cli_query_info_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + in_max_output_length); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_read.c b/libcli/smb/smb2cli_read.c index 0adb403..4a31622 100644 --- a/libcli/smb/smb2cli_read.c +++ b/libcli/smb/smb2cli_read.c @@ -72,7 +72,8 @@ struct tevent_req *smb2cli_read_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - state->dyn_pad, sizeof(state->dyn_pad)); + state->dyn_pad, sizeof(state->dyn_pad), + length); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_session.c b/libcli/smb/smb2cli_session.c index 537c171..4418a0d 100644 --- a/libcli/smb/smb2cli_session.c +++ b/libcli/smb/smb2cli_session.c @@ -102,7 +102,8 @@ struct tevent_req *smb2cli_session_setup_send(TALLOC_CTX *mem_ctx, NULL, /* tcon */ session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + UINT16_MAX); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } @@ -258,7 +259,8 @@ struct tevent_req *smb2cli_logoff_send(TALLOC_CTX *mem_ctx, NULL, /* tcon */ session, state->fixed, sizeof(state->fixed), - NULL, 0); + NULL, 0, /* dyn* */ + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_set_info.c b/libcli/smb/smb2cli_set_info.c index d5c7e58..6871370 100644 --- a/libcli/smb/smb2cli_set_info.c +++ b/libcli/smb/smb2cli_set_info.c @@ -88,7 +88,8 @@ struct tevent_req *smb2cli_set_info_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smb2cli_write.c b/libcli/smb/smb2cli_write.c index 89137bd..6d0a0aa 100644 --- a/libcli/smb/smb2cli_write.c +++ b/libcli/smb/smb2cli_write.c @@ -82,7 +82,8 @@ struct tevent_req *smb2cli_write_send(TALLOC_CTX *mem_ctx, tcon, session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 60c1c9f..f64852b 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -2983,11 +2983,11 @@ struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx, const uint8_t *fixed, uint16_t fixed_len, const uint8_t *dyn, - uint32_t dyn_len) + uint32_t dyn_len, + uint32_t max_dyn_len) { struct tevent_req *req; NTSTATUS status; - uint32_t max_dyn_len = 0; req = smb2cli_req_create(mem_ctx, ev, conn, cmd, additional_flags, clear_flags, @@ -4259,7 +4259,8 @@ static struct tevent_req *smbXcli_negprot_smb2_subreq(struct smbXcli_negprot_sta state->timeout_msec, NULL, NULL, /* tcon, session */ state->smb2.fixed, sizeof(state->smb2.fixed), - state->smb2.dyn, dialect_count*2); + state->smb2.dyn, dialect_count*2, + UINT16_MAX); /* max_dyn_len */ } static void smbXcli_negprot_smb2_done(struct tevent_req *subreq) diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index 017c0f0..4ce39c0 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -242,7 +242,8 @@ struct tevent_req *smb2cli_req_send(TALLOC_CTX *mem_ctx, const uint8_t *fixed, uint16_t fixed_len, const uint8_t *dyn, - uint32_t dyn_len); + uint32_t dyn_len, + uint32_t max_dyn_len); NTSTATUS smb2cli_req_recv(struct tevent_req *req, TALLOC_CTX *mem_ctx, struct iovec **piov, const struct smb2cli_req_expected_response *expected, diff --git a/source3/libsmb/smb2cli_tcon.c b/source3/libsmb/smb2cli_tcon.c index ab97f8d..b3136fa 100644 --- a/source3/libsmb/smb2cli_tcon.c +++ b/source3/libsmb/smb2cli_tcon.c @@ -85,7 +85,8 @@ struct tevent_req *smb2cli_tcon_send(TALLOC_CTX *mem_ctx, NULL, /* tcon */ cli->smb2.session, state->fixed, sizeof(state->fixed), - dyn, dyn_len); + dyn, dyn_len, + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } @@ -211,7 +212,8 @@ struct tevent_req *smb2cli_tdis_send(TALLOC_CTX *mem_ctx, cli->smb2.tcon, cli->smb2.session, state->fixed, sizeof(state->fixed), - NULL, 0); + NULL, 0, /* dyn* */ + 0); /* max_dyn_len */ if (tevent_req_nomem(subreq, req)) { return tevent_req_post(req, ev); } diff --git a/source4/libcli/smb2/transport.c b/source4/libcli/smb2/transport.c index bdab523..2ad16a9 100644 --- a/source4/libcli/smb2/transport.c +++ b/source4/libcli/smb2/transport.c @@ -151,7 +151,8 @@ void smb2_transport_send(struct smb2_request *req) NULL, /* body */ 0, /* body_fixed */ NULL, /* dyn */ - 0); /* dyn_len */ + 0, /* dyn_len */ + 0); /* max_dyn_len */ if (subreq != NULL) { smbXcli_req_set_pending(subreq); tevent_req_set_callback(subreq, @@ -190,7 +191,8 @@ void smb2_transport_send(struct smb2_request *req) tcon, session, body.data, body.length, - dyn.data, dyn.length); + dyn.data, dyn.length, + 0); /* max_dyn_len */ if (req->subreq == NULL) { req->state = SMB2_REQUEST_ERROR; req->status = NT_STATUS_NO_MEMORY; @@ -347,7 +349,8 @@ static void smb2_transport_break_handler(struct tevent_req *subreq) NULL, /* body */ 0, /* body_fixed */ NULL, /* dyn */ - 0); /* dyn_len */ + 0, /* dyn_len */ + 0); /* max_dyn_len */ if (subreq != NULL) { smbXcli_req_set_pending(subreq); tevent_req_set_callback(subreq, -- 1.7.9.5 From d0ed01a5cf3ebfbbc62aeeb0e16e97c5ead6442f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 14:05:05 +0200 Subject: [PATCH 18/57] libcli/smb: add smb1cli_conn_req_possible() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 111f529a2a5832b822445bb4f63b142d8ccb2cb7) --- libcli/smb/smbXcli_base.c | 17 +++++++++++++++++ libcli/smb/smbXcli_base.h | 1 + 2 files changed, 18 insertions(+) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index f64852b..028f152 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -595,6 +595,23 @@ uint32_t smb1cli_conn_max_xmit(struct smbXcli_conn *conn) return conn->smb1.max_xmit; } +bool smb1cli_conn_req_possible(struct smbXcli_conn *conn) +{ + size_t pending; + uint16_t possible = conn->smb1.server.max_mux; + + pending = tevent_queue_length(conn->outgoing); + if (pending >= possible) { + return false; + } + pending += talloc_array_length(conn->pending); + if (pending >= possible) { + return false; + } + + return true; +} + uint32_t smb1cli_conn_server_session_key(struct smbXcli_conn *conn) { return conn->smb1.server.session_key; diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index 4ce39c0..6b3156f 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -69,6 +69,7 @@ bool smbXcli_req_set_pending(struct tevent_req *req); uint32_t smb1cli_conn_capabilities(struct smbXcli_conn *conn); uint32_t smb1cli_conn_max_xmit(struct smbXcli_conn *conn); +bool smb1cli_conn_req_possible(struct smbXcli_conn *conn); uint32_t smb1cli_conn_server_session_key(struct smbXcli_conn *conn); const uint8_t *smb1cli_conn_server_challenge(struct smbXcli_conn *conn); uint16_t smb1cli_conn_server_security_mode(struct smbXcli_conn *conn); -- 1.7.9.5 From b6e81741c37e0d9c0bdb6b27a561a71ca20ea1b7 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 15:49:19 +0200 Subject: [PATCH 19/57] libcli/smb: add smb2cli_conn_req_possible() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 7efdc323d1a1abdae70bcafefe07b3cffcdb2521) --- libcli/smb/smbXcli_base.c | 22 ++++++++++++++++++++++ libcli/smb/smbXcli_base.h | 1 + 2 files changed, 23 insertions(+) diff --git a/libcli/smb/smbXcli_base.c b/libcli/smb/smbXcli_base.c index 028f152..b502f4f 100644 --- a/libcli/smb/smbXcli_base.c +++ b/libcli/smb/smbXcli_base.c @@ -2452,6 +2452,28 @@ bool smbXcli_conn_has_async_calls(struct smbXcli_conn *conn) || (talloc_array_length(conn->pending) != 0)); } +bool smb2cli_conn_req_possible(struct smbXcli_conn *conn, uint32_t *max_dyn_len) +{ + uint16_t credits = 1; + + if (conn->smb2.cur_credits == 0) { + if (max_dyn_len != NULL) { + *max_dyn_len = 0; + } + return false; + } + + if (conn->smb2.server.capabilities & SMB2_CAP_LARGE_MTU) { + credits = conn->smb2.cur_credits; + } + + if (max_dyn_len != NULL) { + *max_dyn_len = credits * 65536; + } + + return true; +} + uint32_t smb2cli_conn_server_capabilities(struct smbXcli_conn *conn) { return conn->smb2.server.capabilities; diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h index 6b3156f..a7cfcc3 100644 --- a/libcli/smb/smbXcli_base.h +++ b/libcli/smb/smbXcli_base.h @@ -199,6 +199,7 @@ NTSTATUS smb1cli_echo_recv(struct tevent_req *req); NTSTATUS smb1cli_echo(struct smbXcli_conn *conn, uint32_t timeout_msec, uint16_t num_echos, DATA_BLOB data); +bool smb2cli_conn_req_possible(struct smbXcli_conn *conn, uint32_t *max_dyn_len); uint32_t smb2cli_conn_server_capabilities(struct smbXcli_conn *conn); uint16_t smb2cli_conn_server_security_mode(struct smbXcli_conn *conn); uint32_t smb2cli_conn_max_trans_size(struct smbXcli_conn *conn); -- 1.7.9.5 From 5c38ce6c450683b5b7c26744a3e8ea890f383de4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 14:10:59 +0200 Subject: [PATCH 20/57] s3:libsmb: rewrite cli_push* to use smb1cli_conn_req_possible() This works out if it's possible to ship the next request dynamically instead of relying on fixed values. The default window size is 16 MByte. We limit the number of outstanding chunks/requests to 256. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit b846b3acd2b217a0d67c1e8fcb039e03498c4e47) --- source3/libsmb/clireadwrite.c | 288 ++++++++++++++++++++++++++--------------- 1 file changed, 187 insertions(+), 101 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 47e7f1b..550c52b 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -1092,13 +1092,7 @@ NTSTATUS cli_writeall(struct cli_state *cli, uint16_t fnum, uint16_t mode, return status; } -struct cli_push_write_state { - struct tevent_req *req;/* This is the main request! Not the subreq */ - uint32_t idx; - off_t ofs; - uint8_t *buf; - size_t size; -}; +struct cli_push_chunk; struct cli_push_state { struct tevent_context *ev; @@ -1106,7 +1100,6 @@ struct cli_push_state { uint16_t fnum; uint16_t mode; off_t start_offset; - size_t window_size; size_t (*source)(uint8_t *buf, size_t n, void *priv); void *priv; @@ -1118,62 +1111,32 @@ struct cli_push_state { /* * Outstanding requests + * + * The maximum is 256: + * - which would be a window of 256 MByte + * for SMB2 with multi-credit + * or smb1 unix extentions. */ - uint32_t pending; - uint16_t max_reqs; - uint32_t num_reqs; - struct cli_push_write_state **reqs; + uint16_t max_chunks; + uint16_t num_chunks; + uint16_t num_waiting; + struct cli_push_chunk *chunks; }; -static void cli_push_written(struct tevent_req *req); - -static bool cli_push_write_setup(struct tevent_req *req, - struct cli_push_state *state, - uint32_t idx) -{ - struct cli_push_write_state *substate; +struct cli_push_chunk { + struct cli_push_chunk *prev, *next; + struct tevent_req *req;/* This is the main request! Not the subreq */ struct tevent_req *subreq; + off_t ofs; + uint8_t *buf; + size_t total_size; + size_t tmp_size; + bool done; +}; - substate = talloc(state->reqs, struct cli_push_write_state); - if (!substate) { - return false; - } - substate->req = req; - substate->idx = idx; - substate->ofs = state->next_offset; - substate->buf = talloc_array(substate, uint8_t, state->chunk_size); - if (!substate->buf) { - talloc_free(substate); - return false; - } - substate->size = state->source(substate->buf, - state->chunk_size, - state->priv); - if (substate->size == 0) { - state->eof = true; - /* nothing to send */ - talloc_free(substate); - return true; - } - - subreq = cli_writeall_send(substate, - state->ev, state->cli, - state->fnum, state->mode, - substate->buf, - substate->ofs, - substate->size); - if (!subreq) { - talloc_free(substate); - return false; - } - tevent_req_set_callback(subreq, cli_push_written, substate); - - state->reqs[idx] = substate; - state->pending += 1; - state->next_offset += substate->size; - - return true; -} +static void cli_push_setup_chunks(struct tevent_req *req); +static void cli_push_chunk_ship(struct cli_push_chunk *chunk); +static void cli_push_chunk_done(struct tevent_req *subreq); struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli, @@ -1185,8 +1148,8 @@ struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, { struct tevent_req *req; struct cli_push_state *state; - uint32_t i; size_t page_size = 1024; + uint64_t tmp64; req = tevent_req_create(mem_ctx, &state, struct cli_push_state); if (req == NULL) { @@ -1199,8 +1162,6 @@ struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, state->mode = mode; state->source = source; state->priv = priv; - state->eof = false; - state->pending = 0; state->next_offset = start_offset; state->chunk_size = cli_write_max_bufsize(cli, mode, 14); @@ -1208,77 +1169,202 @@ struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, state->chunk_size &= ~(page_size - 1); } - state->max_reqs = smbXcli_conn_max_requests(cli->conn); - if (window_size == 0) { - window_size = state->max_reqs * state->chunk_size; + /* + * We use 16 MByte as default window size. + */ + window_size = 16 * 1024 * 1024; } - state->num_reqs = window_size/state->chunk_size; + + tmp64 = window_size/state->chunk_size; if ((window_size % state->chunk_size) > 0) { - state->num_reqs += 1; + tmp64 += 1; } - state->num_reqs = MIN(state->num_reqs, state->max_reqs); - state->num_reqs = MAX(state->num_reqs, 1); + tmp64 = MAX(tmp64, 1); + tmp64 = MIN(tmp64, 256); + state->max_chunks = tmp64; - state->reqs = talloc_zero_array(state, struct cli_push_write_state *, - state->num_reqs); - if (state->reqs == NULL) { - goto failed; + /* + * We defer the callback because of the complex + * substate/subfunction logic + */ + tevent_req_defer_callback(req, ev); + + cli_push_setup_chunks(req); + if (!tevent_req_is_in_progress(req)) { + return tevent_req_post(req, ev); } - for (i=0; inum_reqs; i++) { - if (!cli_push_write_setup(req, state, i)) { - goto failed; + return req; +} + +static void cli_push_setup_chunks(struct tevent_req *req) +{ + struct cli_push_state *state = + tevent_req_data(req, + struct cli_push_state); + struct cli_push_chunk *chunk, *next = NULL; + size_t i; + + for (chunk = state->chunks; chunk; chunk = next) { + /* + * Note that chunk might be removed from this call. + */ + next = chunk->next; + cli_push_chunk_ship(chunk); + if (!tevent_req_is_in_progress(req)) { + return; + } + } + + for (i = state->num_chunks; i < state->max_chunks; i++) { + + if (state->num_waiting > 0) { + return; } if (state->eof) { break; } + + chunk = talloc_zero(state, struct cli_push_chunk); + if (tevent_req_nomem(chunk, req)) { + return; + } + chunk->req = req; + chunk->ofs = state->next_offset; + chunk->buf = talloc_array(chunk, + uint8_t, + state->chunk_size); + if (tevent_req_nomem(chunk->buf, req)) { + return; + } + chunk->total_size = state->source(chunk->buf, + state->chunk_size, + state->priv); + if (chunk->total_size == 0) { + /* nothing to send */ + talloc_free(chunk); + state->eof = true; + break; + } + state->next_offset += chunk->total_size; + + DLIST_ADD_END(state->chunks, chunk, NULL); + state->num_chunks++; + state->num_waiting++; + + cli_push_chunk_ship(chunk); + if (!tevent_req_is_in_progress(req)) { + return; + } } - if (state->pending == 0) { - tevent_req_done(req); - return tevent_req_post(req, ev); + if (!state->eof) { + return; } - return req; + if (state->num_chunks > 0) { + return; + } + + tevent_req_done(req); +} + +static void cli_push_chunk_ship(struct cli_push_chunk *chunk) +{ + struct tevent_req *req = chunk->req; + struct cli_push_state *state = + tevent_req_data(req, + struct cli_push_state); + bool ok; + const uint8_t *buf; + off_t ofs; + size_t size; + + if (chunk->done) { + DLIST_REMOVE(state->chunks, chunk); + SMB_ASSERT(state->num_chunks > 0); + state->num_chunks--; + TALLOC_FREE(chunk); + + return; + } + + if (chunk->subreq != NULL) { + return; + } + + SMB_ASSERT(state->num_waiting > 0); + + buf = chunk->buf + chunk->tmp_size; + ofs = chunk->ofs + chunk->tmp_size; + size = chunk->total_size - chunk->tmp_size; + + ok = smb1cli_conn_req_possible(state->cli->conn); + if (!ok) { + return; + } + + chunk->subreq = cli_write_andx_send(chunk, + state->ev, + state->cli, + state->fnum, + state->mode, + buf, + ofs, + size); + if (tevent_req_nomem(chunk->subreq, req)) { + return; + } + tevent_req_set_callback(chunk->subreq, + cli_push_chunk_done, + chunk); - failed: - tevent_req_nterror(req, NT_STATUS_NO_MEMORY); - return tevent_req_post(req, ev); + state->num_waiting--; + return; } -static void cli_push_written(struct tevent_req *subreq) +static void cli_push_chunk_done(struct tevent_req *subreq) { - struct cli_push_write_state *substate = tevent_req_callback_data( - subreq, struct cli_push_write_state); - struct tevent_req *req = substate->req; - struct cli_push_state *state = tevent_req_data( - req, struct cli_push_state); + struct cli_push_chunk *chunk = + tevent_req_callback_data(subreq, + struct cli_push_chunk); + struct tevent_req *req = chunk->req; + struct cli_push_state *state = + tevent_req_data(req, + struct cli_push_state); NTSTATUS status; - uint32_t idx = substate->idx; + size_t expected = chunk->total_size - chunk->tmp_size; + size_t written; - state->reqs[idx] = NULL; - state->pending -= 1; + chunk->subreq = NULL; - status = cli_writeall_recv(subreq, NULL); + status = cli_write_andx_recv(subreq, &written); TALLOC_FREE(subreq); - TALLOC_FREE(substate); if (tevent_req_nterror(req, status)) { return; } - if (!state->eof) { - if (!cli_push_write_setup(req, state, idx)) { - tevent_req_nterror(req, NT_STATUS_NO_MEMORY); - return; - } + if (written > expected) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; } - if (state->pending == 0) { - tevent_req_done(req); + if (written == 0) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); return; } + + chunk->tmp_size += written; + + if (chunk->tmp_size == chunk->total_size) { + chunk->done = true; + } else { + state->num_waiting++; + } + + cli_push_setup_chunks(req); } NTSTATUS cli_push_recv(struct tevent_req *req) -- 1.7.9.5 From 404d40580b643433228a1c59060f18757bd52de0 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 18:03:50 +0200 Subject: [PATCH 21/57] s3:libsmb: rewrite cli_pull* to use smb1cli_conn_req_possible() This works out if it's possible to ship the next request dynamically instead of relying on fixed values. The default window size is 16 MByte. We limit the number of outstanding chunks/requests to 256. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 8062aefbe3c2fcc73e3d19af6663c8736c570f7c) --- source3/libsmb/clireadwrite.c | 417 ++++++++++++++++++++++++----------------- 1 file changed, 246 insertions(+), 171 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 550c52b..dd5d4c2 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -388,23 +388,9 @@ static NTSTATUS cli_readall_recv(struct tevent_req *req, ssize_t *received, return NT_STATUS_OK; } -struct cli_pull_subreq { - struct tevent_req *req; - ssize_t received; - uint8_t *buf; -}; - -/* - * Parallel read support. - * - * cli_pull sends as many read&x requests as the server would allow via - * max_mux at a time. When replies flow back in, the data is written into - * the callback function "sink" in the right order. - */ +struct cli_pull_chunk; struct cli_pull_state { - struct tevent_req *req; - struct tevent_context *ev; struct cli_state *cli; uint16_t fnum; @@ -415,54 +401,49 @@ struct cli_pull_state { void *priv; size_t chunk_size; + off_t next_offset; + off_t remaining; /* - * Outstanding requests - */ - uint16_t max_reqs; - int num_reqs; - struct cli_pull_subreq *reqs; - - /* - * For how many bytes did we send requests already? - */ - off_t requested; - - /* - * Next request index to push into "sink". This walks around the "req" - * array, taking care that the requests are pushed to "sink" in the - * right order. If necessary (i.e. replies don't come in in the right - * order), replies are held back in "reqs". + * How many bytes did we push into "sink"? */ - int top_req; + off_t pushed; /* - * How many bytes did we push into "sink"? + * Outstanding requests + * + * The maximum is 256: + * - which would be a window of 256 MByte + * for SMB2 with multi-credit + * or smb1 unix extentions. */ - - off_t pushed; + uint16_t max_chunks; + uint16_t num_chunks; + uint16_t num_waiting; + struct cli_pull_chunk *chunks; }; -static char *cli_pull_print(struct tevent_req *req, TALLOC_CTX *mem_ctx) -{ - struct cli_pull_state *state = tevent_req_data( - req, struct cli_pull_state); - char *result; - - result = tevent_req_default_print(req, mem_ctx); - if (result == NULL) { - return NULL; - } - - return talloc_asprintf_append_buffer( - result, "num_reqs=%d, top_req=%d", - state->num_reqs, state->top_req); -} +struct cli_pull_chunk { + struct cli_pull_chunk *prev, *next; + struct tevent_req *req;/* This is the main request! Not the subreq */ + struct tevent_req *subreq; + off_t ofs; + uint8_t *buf; + size_t total_size; + size_t tmp_size; + bool done; +}; -static void cli_pull_read_done(struct tevent_req *read_req); +static void cli_pull_setup_chunks(struct tevent_req *req); +static void cli_pull_chunk_ship(struct cli_pull_chunk *chunk); +static void cli_pull_chunk_done(struct tevent_req *subreq); /* - * Prepare an async pull request + * Parallel read support. + * + * cli_pull sends as many read&x requests as the server would allow via + * max_mux at a time. When replies flow back in, the data is written into + * the callback function "sink" in the right order. */ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, @@ -476,16 +457,13 @@ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, { struct tevent_req *req; struct cli_pull_state *state; - int i; size_t page_size = 1024; + uint64_t tmp64; req = tevent_req_create(mem_ctx, &state, struct cli_pull_state); if (req == NULL) { return NULL; } - tevent_req_set_print_fn(req, cli_pull_print); - state->req = req; - state->cli = cli; state->ev = ev; state->fnum = fnum; @@ -493,9 +471,8 @@ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, state->size = size; state->sink = sink; state->priv = priv; - - state->pushed = 0; - state->top_req = 0; + state->next_offset = start_offset; + state->remaining = size; if (size == 0) { tevent_req_done(req); @@ -507,155 +484,251 @@ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, state->chunk_size &= ~(page_size - 1); } - state->max_reqs = smbXcli_conn_max_requests(cli->conn); + if (window_size == 0) { + /* + * We use 16 MByte as default window size. + */ + window_size = 16 * 1024 * 1024; + } + + tmp64 = window_size/state->chunk_size; + if ((window_size % state->chunk_size) > 0) { + tmp64 += 1; + } + tmp64 = MAX(tmp64, 1); + tmp64 = MIN(tmp64, 256); + state->max_chunks = tmp64; + + /* + * We defer the callback because of the complex + * substate/subfunction logic + */ + tevent_req_defer_callback(req, ev); + + cli_pull_setup_chunks(req); + if (!tevent_req_is_in_progress(req)) { + return tevent_req_post(req, ev); + } + + return req; +} - state->num_reqs = MAX(window_size/state->chunk_size, 1); - state->num_reqs = MIN(state->num_reqs, state->max_reqs); +static void cli_pull_setup_chunks(struct tevent_req *req) +{ + struct cli_pull_state *state = + tevent_req_data(req, + struct cli_pull_state); + struct cli_pull_chunk *chunk, *next = NULL; + size_t i; - state->reqs = talloc_zero_array(state, struct cli_pull_subreq, - state->num_reqs); - if (state->reqs == NULL) { - goto failed; + for (chunk = state->chunks; chunk; chunk = next) { + /* + * Note that chunk might be removed from this call. + */ + next = chunk->next; + cli_pull_chunk_ship(chunk); + if (!tevent_req_is_in_progress(req)) { + return; + } } - state->requested = 0; + for (i = state->num_chunks; i < state->max_chunks; i++) { - for (i=0; inum_reqs; i++) { - struct cli_pull_subreq *subreq = &state->reqs[i]; - off_t size_left; - size_t request_thistime; + if (state->num_waiting > 0) { + return; + } - if (state->requested >= size) { - state->num_reqs = i; + if (state->remaining == 0) { break; } - size_left = size - state->requested; - request_thistime = MIN(size_left, state->chunk_size); + chunk = talloc_zero(state, struct cli_pull_chunk); + if (tevent_req_nomem(chunk, req)) { + return; + } + chunk->req = req; + chunk->ofs = state->next_offset; + chunk->total_size = MIN(state->remaining, state->chunk_size); + state->next_offset += chunk->total_size; + state->remaining -= chunk->total_size; - subreq->req = cli_readall_send( - state->reqs, ev, cli, fnum, - state->start_offset + state->requested, - request_thistime); + DLIST_ADD_END(state->chunks, chunk, NULL); + state->num_chunks++; + state->num_waiting++; - if (subreq->req == NULL) { - goto failed; + cli_pull_chunk_ship(chunk); + if (!tevent_req_is_in_progress(req)) { + return; } - tevent_req_set_callback(subreq->req, cli_pull_read_done, req); - state->requested += request_thistime; } - return req; -failed: - TALLOC_FREE(req); - return NULL; -} + if (state->remaining > 0) { + return; + } -/* - * Handle incoming read replies, push the data into sink and send out new - * requests if necessary. - */ + if (state->num_chunks > 0) { + return; + } + + tevent_req_done(req); +} -static void cli_pull_read_done(struct tevent_req *subreq) +static void cli_pull_chunk_ship(struct cli_pull_chunk *chunk) { - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct cli_pull_state *state = tevent_req_data( - req, struct cli_pull_state); - struct cli_pull_subreq *pull_subreq = NULL; - NTSTATUS status; - int i; + struct tevent_req *req = chunk->req; + struct cli_pull_state *state = + tevent_req_data(req, + struct cli_pull_state); + bool ok; + off_t ofs; + size_t size; - for (i = 0; i < state->num_reqs; i++) { - pull_subreq = &state->reqs[i]; - if (subreq == pull_subreq->req) { - break; + if (chunk->done) { + NTSTATUS status; + + if (chunk != state->chunks) { + /* + * this chunk is not the + * first one in the list. + * + * which means we should not + * push it into the sink yet. + */ + return; + } + + if (chunk->tmp_size == 0) { + /* + * we git a short read, we're done + */ + tevent_req_done(req); + return; } + + status = state->sink((char *)chunk->buf, + chunk->tmp_size, + state->priv); + if (tevent_req_nterror(req, status)) { + return; + } + state->pushed += chunk->tmp_size; + + if (chunk->tmp_size < chunk->total_size) { + /* + * we git a short read, we're done + */ + tevent_req_done(req); + return; + } + + DLIST_REMOVE(state->chunks, chunk); + SMB_ASSERT(state->num_chunks > 0); + state->num_chunks--; + TALLOC_FREE(chunk); + + return; } - if (i == state->num_reqs) { - /* Huh -- received something we did not send?? */ - tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR); + + if (chunk->subreq != NULL) { return; } - status = cli_readall_recv(subreq, &pull_subreq->received, - &pull_subreq->buf); - if (!NT_STATUS_IS_OK(status)) { - tevent_req_nterror(state->req, status); + SMB_ASSERT(state->num_waiting > 0); + + ofs = chunk->ofs + chunk->tmp_size; + size = chunk->total_size - chunk->tmp_size; + + ok = smb1cli_conn_req_possible(state->cli->conn); + if (!ok) { return; } - /* - * This loop is the one to take care of out-of-order replies. All - * pending requests are in state->reqs, state->reqs[top_req] is the - * one that is to be pushed next. If however a request later than - * top_req is replied to, then we can't push yet. If top_req is - * replied to at a later point then, we need to push all the finished - * requests. - */ + chunk->subreq = cli_read_andx_send(chunk, + state->ev, + state->cli, + state->fnum, + ofs, + size); + if (tevent_req_nomem(chunk->subreq, req)) { + return; + } + tevent_req_set_callback(chunk->subreq, + cli_pull_chunk_done, + chunk); - while (state->reqs[state->top_req].req != NULL) { - struct cli_pull_subreq *top_subreq; + state->num_waiting--; + return; +} - DEBUG(11, ("cli_pull_read_done: top_req = %d\n", - state->top_req)); +static void cli_pull_chunk_done(struct tevent_req *subreq) +{ + struct cli_pull_chunk *chunk = + tevent_req_callback_data(subreq, + struct cli_pull_chunk); + struct tevent_req *req = chunk->req; + struct cli_pull_state *state = + tevent_req_data(req, + struct cli_pull_state); + NTSTATUS status; + size_t expected = chunk->total_size - chunk->tmp_size; + ssize_t received; + uint8_t *buf = NULL; - top_subreq = &state->reqs[state->top_req]; + chunk->subreq = NULL; - if (tevent_req_is_in_progress(top_subreq->req)) { - DEBUG(11, ("cli_pull_read_done: top request not yet " - "done\n")); - return; - } + status = cli_read_andx_recv(subreq, &received, &buf); + if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) { + received = 0; + status = NT_STATUS_OK; + } + if (tevent_req_nterror(req, status)) { + return; + } + + if (received > expected) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } - DEBUG(10, ("cli_pull_read_done: Pushing %d bytes, %d already " - "pushed\n", (int)top_subreq->received, - (int)state->pushed)); + if (received == 0) { + /* + * We got EOF we're done + */ + chunk->done = true; + cli_pull_setup_chunks(req); + return; + } - status = state->sink((char *)top_subreq->buf, - top_subreq->received, state->priv); - if (tevent_req_nterror(state->req, status)) { + if (received == chunk->total_size) { + /* + * We got it in the first run. + * + * We don't call TALLOC_FREE(subreq) + * here and keep the returned buffer. + */ + chunk->buf = buf; + } else if (chunk->buf == NULL) { + chunk->buf = talloc_array(chunk, uint8_t, chunk->total_size); + if (tevent_req_nomem(chunk->buf, req)) { return; } - state->pushed += top_subreq->received; - - TALLOC_FREE(state->reqs[state->top_req].req); - - if (state->requested < state->size) { - struct tevent_req *new_req; - off_t size_left; - size_t request_thistime; - - size_left = state->size - state->requested; - request_thistime = MIN(size_left, state->chunk_size); - - DEBUG(10, ("cli_pull_read_done: Requesting %d bytes " - "at %d, position %d\n", - (int)request_thistime, - (int)(state->start_offset - + state->requested), - state->top_req)); - - new_req = cli_readall_send( - state->reqs, state->ev, state->cli, - state->fnum, - state->start_offset + state->requested, - request_thistime); - - if (tevent_req_nomem(new_req, state->req)) { - return; - } - tevent_req_set_callback(new_req, cli_pull_read_done, - req); - - state->reqs[state->top_req].req = new_req; - state->requested += request_thistime; - } + } - state->top_req = (state->top_req+1) % state->num_reqs; + if (received != chunk->total_size) { + uint8_t *p = chunk->buf + chunk->tmp_size; + memcpy(p, buf, received); + TALLOC_FREE(subreq); } - tevent_req_done(req); + chunk->tmp_size += received; + + if (chunk->tmp_size == chunk->total_size) { + chunk->done = true; + } else { + state->num_waiting++; + } + + cli_pull_setup_chunks(req); } NTSTATUS cli_pull_recv(struct tevent_req *req, off_t *received) @@ -665,9 +738,11 @@ NTSTATUS cli_pull_recv(struct tevent_req *req, off_t *received) NTSTATUS status; if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); return status; } *received = state->pushed; + tevent_req_received(req); return NT_STATUS_OK; } -- 1.7.9.5 From a197b9c6d4b956dfe981293602fb3e94a6c9e1a4 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 18:23:55 +0200 Subject: [PATCH 22/57] s3:libsmb: remove unused cli_readall* Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 9193a58375691bfca9e3cce1ff61b2b6dd65a982) --- source3/libsmb/clireadwrite.c | 119 ----------------------------------------- 1 file changed, 119 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index dd5d4c2..10dc79b 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -269,125 +269,6 @@ NTSTATUS cli_read_andx_recv(struct tevent_req *req, ssize_t *received, return NT_STATUS_OK; } -struct cli_readall_state { - struct tevent_context *ev; - struct cli_state *cli; - uint16_t fnum; - off_t start_offset; - size_t size; - size_t received; - uint8_t *buf; -}; - -static void cli_readall_done(struct tevent_req *subreq); - -static struct tevent_req *cli_readall_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct cli_state *cli, - uint16_t fnum, - off_t offset, size_t size) -{ - struct tevent_req *req, *subreq; - struct cli_readall_state *state; - - req = tevent_req_create(mem_ctx, &state, struct cli_readall_state); - if (req == NULL) { - return NULL; - } - state->ev = ev; - state->cli = cli; - state->fnum = fnum; - state->start_offset = offset; - state->size = size; - state->received = 0; - state->buf = NULL; - - subreq = cli_read_andx_send(state, ev, cli, fnum, offset, size); - if (tevent_req_nomem(subreq, req)) { - return tevent_req_post(req, ev); - } - tevent_req_set_callback(subreq, cli_readall_done, req); - return req; -} - -static void cli_readall_done(struct tevent_req *subreq) -{ - struct tevent_req *req = tevent_req_callback_data( - subreq, struct tevent_req); - struct cli_readall_state *state = tevent_req_data( - req, struct cli_readall_state); - ssize_t received; - uint8_t *buf; - NTSTATUS status; - - status = cli_read_andx_recv(subreq, &received, &buf); - if (tevent_req_nterror(req, status)) { - return; - } - - if (received == 0) { - /* EOF */ - tevent_req_done(req); - return; - } - - if ((state->received == 0) && (received == state->size)) { - /* Ideal case: Got it all in one run */ - state->buf = buf; - state->received += received; - tevent_req_done(req); - return; - } - - /* - * We got a short read, issue a read for the - * rest. Unfortunately we have to allocate the buffer - * ourselves now, as our caller expects to receive a single - * buffer. cli_read_andx does it from the buffer received from - * the net, but with a short read we have to put it together - * from several reads. - */ - - if (state->buf == NULL) { - state->buf = talloc_array(state, uint8_t, state->size); - if (tevent_req_nomem(state->buf, req)) { - return; - } - } - memcpy(state->buf + state->received, buf, received); - state->received += received; - - TALLOC_FREE(subreq); - - if (state->received >= state->size) { - tevent_req_done(req); - return; - } - - subreq = cli_read_andx_send(state, state->ev, state->cli, state->fnum, - state->start_offset + state->received, - state->size - state->received); - if (tevent_req_nomem(subreq, req)) { - return; - } - tevent_req_set_callback(subreq, cli_readall_done, req); -} - -static NTSTATUS cli_readall_recv(struct tevent_req *req, ssize_t *received, - uint8_t **rcvbuf) -{ - struct cli_readall_state *state = tevent_req_data( - req, struct cli_readall_state); - NTSTATUS status; - - if (tevent_req_is_nterror(req, &status)) { - return status; - } - *received = state->received; - *rcvbuf = state->buf; - return NT_STATUS_OK; -} - struct cli_pull_chunk; struct cli_pull_state { -- 1.7.9.5 From 3a7c5f92d4fb7c76beaea814ccb0e4fbbe3ad749 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 10:46:28 +0200 Subject: [PATCH 23/57] s3:client: use the default io size Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 9b4692f2d057f31f76db0bdf7c4a515db057e2dd) --- source3/client/client.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source3/client/client.c b/source3/client/client.c index d09d012..5ec2948 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -55,7 +55,7 @@ static bool grepable = false; static char *cmdstr = NULL; const char *cmd_ptr = NULL; -static int io_bufsize = 524288; +static int io_bufsize = 0; /* we use the default size */ static int name_type = 0x20; static int max_protocol = -1; -- 1.7.9.5 From b98c7dfcfa37e4f44a248f7493d861272e064467 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 10:47:11 +0200 Subject: [PATCH 24/57] s3:client: fix compiler warning Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 2394f8788d2f6e21064db0b6099a0dbe3a33e1d6) --- source3/client/client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/client/client.c b/source3/client/client.c index 5ec2948..e91db4a 100644 --- a/source3/client/client.c +++ b/source3/client/client.c @@ -5338,6 +5338,7 @@ static int do_message_op(struct user_auth_info *a_info) int main(int argc,char *argv[]) { + const char **const_argv = discard_const_p(const char *, argv); char *base_directory = NULL; int opt; char *query_host = NULL; @@ -5388,7 +5389,7 @@ static int do_message_op(struct user_auth_info *a_info) popt_common_set_auth_info(auth_info); /* skip argv(0) */ - pc = poptGetContext("smbclient", argc, (const char **) argv, long_options, 0); + pc = poptGetContext("smbclient", argc, const_argv, long_options, 0); poptSetOtherOptionHelp(pc, "service "); while ((opt = poptGetNextOpt(pc)) != -1) { -- 1.7.9.5 From 9f586e6a0f865a4a531011b542251257e683a99e Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 13:48:55 -0700 Subject: [PATCH 25/57] s3:lib: Factor read_ea_list_entry() and read_nttrans_ea_list() out so they can be used by the SMB2 client code. Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit c80349e0fad7c182b0bddefed99a78d95323faca) --- source3/lib/util_ea.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++++ source3/lib/util_ea.h | 36 ++++++++++++++ source3/smbd/nttrans.c | 44 +---------------- source3/smbd/trans2.c | 62 +----------------------- source3/wscript_build | 3 +- 5 files changed, 166 insertions(+), 105 deletions(-) create mode 100644 source3/lib/util_ea.c create mode 100644 source3/lib/util_ea.h diff --git a/source3/lib/util_ea.c b/source3/lib/util_ea.c new file mode 100644 index 0000000..81684da --- /dev/null +++ b/source3/lib/util_ea.c @@ -0,0 +1,126 @@ +/* + Unix SMB/CIFS implementation. + SMB Extended attribute buffer handling + Copyright (C) Jeremy Allison 2005-2013 + Copyright (C) Tim Prouty 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "includes.h" +#include "lib/util_ea.h" + +/**************************************************************************** + Read one EA list entry from the buffer. +****************************************************************************/ + +struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used) +{ + struct ea_list *eal = talloc_zero(ctx, struct ea_list); + uint16 val_len; + unsigned int namelen; + size_t converted_size; + + if (!eal) { + return NULL; + } + + if (data_size < 6) { + return NULL; + } + + eal->ea.flags = CVAL(pdata,0); + namelen = CVAL(pdata,1); + val_len = SVAL(pdata,2); + + if (4 + namelen + 1 + val_len > data_size) { + return NULL; + } + + /* Ensure the name is null terminated. */ + if (pdata[namelen + 4] != '\0') { + return NULL; + } + if (!pull_ascii_talloc(ctx, &eal->ea.name, pdata + 4, &converted_size)) { + DEBUG(0,("read_ea_list_entry: pull_ascii_talloc failed: %s", + strerror(errno))); + } + if (!eal->ea.name) { + return NULL; + } + + eal->ea.value = data_blob_talloc(eal, NULL, (size_t)val_len + 1); + if (!eal->ea.value.data) { + return NULL; + } + + memcpy(eal->ea.value.data, pdata + 4 + namelen + 1, val_len); + + /* Ensure we're null terminated just in case we print the value. */ + eal->ea.value.data[val_len] = '\0'; + /* But don't count the null. */ + eal->ea.value.length--; + + if (pbytes_used) { + *pbytes_used = 4 + namelen + 1 + val_len; + } + + DEBUG(10,("read_ea_list_entry: read ea name %s\n", eal->ea.name)); + dump_data(10, eal->ea.value.data, eal->ea.value.length); + + return eal; +} + +/**************************************************************************** + Read a list of EA names and data from an incoming data buffer. Create an ea_list with them. +****************************************************************************/ + +struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size) +{ + struct ea_list *ea_list_head = NULL; + size_t offset = 0; + + if (data_size < 4) { + return NULL; + } + + while (offset + 4 <= data_size) { + size_t next_offset = IVAL(pdata,offset); + struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset + 4, data_size - offset - 4, NULL); + + if (!eal) { + return NULL; + } + + DLIST_ADD_END(ea_list_head, eal, struct ea_list *); + if (next_offset == 0) { + break; + } + + /* Integer wrap protection for the increment. */ + if (offset + next_offset < offset) { + break; + } + + offset += next_offset; + + /* Integer wrap protection for while loop. */ + if (offset + 4 < offset) { + break; + } + + } + + return ea_list_head; +} diff --git a/source3/lib/util_ea.h b/source3/lib/util_ea.h new file mode 100644 index 0000000..54423ac --- /dev/null +++ b/source3/lib/util_ea.h @@ -0,0 +1,36 @@ +/* + Unix SMB/CIFS implementation. + SMB Extended attribute buffer handling + Copyright (C) Jeremy Allison 2005-2013 + Copyright (C) Tim Prouty 2008 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __LIB_UTIL_EA_H__ +#define __LIB_UTIL_EA_H__ + +/**************************************************************************** + Read one EA list entry from a buffer. +****************************************************************************/ + +struct ea_list *read_ea_list_entry(TALLOC_CTX *ctx, const char *pdata, size_t data_size, size_t *pbytes_used); + +/**************************************************************************** + Read a list of EA names and data from an incoming data buffer. Create an ea_list with them. +****************************************************************************/ + +struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size); + +#endif /* __LIB_UTIL_EA_H__ */ diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c index f4b0456..42cd25b 100644 --- a/source3/smbd/nttrans.c +++ b/source3/smbd/nttrans.c @@ -29,6 +29,7 @@ #include "auth.h" #include "smbprofile.h" #include "libsmb/libsmb.h" +#include "lib/util_ea.h" extern const struct generic_mapping file_generic_mapping; @@ -965,49 +966,6 @@ NTSTATUS set_sd_blob(files_struct *fsp, uint8_t *data, uint32_t sd_len, } /**************************************************************************** - Read a list of EA names and data from an incoming data buffer. Create an ea_list with them. -****************************************************************************/ - -struct ea_list *read_nttrans_ea_list(TALLOC_CTX *ctx, const char *pdata, size_t data_size) -{ - struct ea_list *ea_list_head = NULL; - size_t offset = 0; - - if (data_size < 4) { - return NULL; - } - - while (offset + 4 <= data_size) { - size_t next_offset = IVAL(pdata,offset); - struct ea_list *eal = read_ea_list_entry(ctx, pdata + offset + 4, data_size - offset - 4, NULL); - - if (!eal) { - return NULL; - } - - DLIST_ADD_END(ea_list_head, eal, struct ea_list *); - if (next_offset == 0) { - break; - } - - /* Integer wrap protection for the increment. */ - if (offset + next_offset < offset) { - break; - } - - offset += next_offset; - - /* Integer wrap protection for while loop. */ - if (offset + 4 < offset) { - break; - } - - } - - return ea_list_head; -} - -/**************************************************************************** Reply to a NT_TRANSACT_CREATE call (needs to process SD's). ****************************************************************************/ diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 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.7.9.5 From b2537feabc3f99dfcf9b165dc6a7d3cb8d8fee8d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 15:54:05 -0700 Subject: [PATCH 26/57] s3:libsmb: Add in the core of the libsmb client SMB2 functions. These create a synchronous cli_smb2_XXX() style interface designed to plug directly into the libsmb/cliXXXX.c code. https://bugzilla.samba.org/show_bug.cgi?id=9974 Signed-off-by: Jeremy Allison Signed-off-by: Stefan Metzmacher (cherry picked from commit 28591dfd5d2163d9181d45d64a4a750e335b7c56) --- source3/include/client.h | 1 + source3/libsmb/cli_smb2_fnum.c | 2373 ++++++++++++++++++++++++++++++++++++++++ source3/libsmb/cli_smb2_fnum.h | 161 +++ source3/libsmb/clirap.c | 7 +- source3/libsmb/clirap.h | 4 + source3/libsmb/libsmb.h | 1 + source3/wscript_build | 3 +- 7 files changed, 2543 insertions(+), 7 deletions(-) create mode 100644 source3/libsmb/cli_smb2_fnum.c create mode 100644 source3/libsmb/cli_smb2_fnum.h diff --git a/source3/include/client.h b/source3/include/client.h index 52e2212..09f9660 100644 --- a/source3/include/client.h +++ b/source3/include/client.h @@ -109,6 +109,7 @@ struct cli_state { struct { struct smbXcli_session *session; struct smbXcli_tcon *tcon; + struct idr_context *open_handles; } smb2; }; diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c new file mode 100644 index 0000000..d0b744b --- /dev/null +++ b/source3/libsmb/cli_smb2_fnum.c @@ -0,0 +1,2373 @@ +/* + Unix SMB/CIFS implementation. + smb2 lib + Copyright (C) Jeremy Allison 2013 + Copyright (C) Volker Lendecke 2013 + Copyright (C) Stefan Metzmacher 2013 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +/* + This code is a thin wrapper around the existing + cli_smb2_XXXX() functions in libcli/smb/smb2cli_XXXXX.c, + but allows the handles to be mapped to uint16_t fnums, + which are easier for smbclient to use. +*/ + +#include "includes.h" +#include "client.h" +#include "async_smb.h" +#include "../libcli/smb/smbXcli_base.h" +#include "smb2cli.h" +#include "cli_smb2_fnum.h" +#include "trans2.h" +#include "clirap.h" +#include "../libcli/smb/smb2_create_blob.h" +#include "libsmb/proto.h" +#include "lib/util/tevent_ntstatus.h" +#include "../libcli/security/security.h" +#include "lib/util_ea.h" + +struct smb2_hnd { + uint64_t fid_persistent; + uint64_t fid_volatile; +}; + +/* + * Handle mapping code. + */ + +/*************************************************************** + Allocate a new fnum between 1 and 0xFFFE from an smb2_hnd. + Ensures handle is owned by cli struct. +***************************************************************/ + +static NTSTATUS map_smb2_handle_to_fnum(struct cli_state *cli, + const struct smb2_hnd *ph, /* In */ + uint16_t *pfnum) /* Out */ +{ + int ret; + struct idr_context *idp = cli->smb2.open_handles; + struct smb2_hnd *owned_h = talloc_memdup(cli, + ph, + sizeof(struct smb2_hnd)); + + if (owned_h == NULL) { + return NT_STATUS_NO_MEMORY; + } + + if (idp == NULL) { + /* Lazy init */ + cli->smb2.open_handles = idr_init(cli); + if (cli->smb2.open_handles == NULL) { + TALLOC_FREE(owned_h); + return NT_STATUS_NO_MEMORY; + } + idp = cli->smb2.open_handles; + } + + ret = idr_get_new_above(idp, owned_h, 1, 0xFFFE); + if (ret == -1) { + TALLOC_FREE(owned_h); + return NT_STATUS_NO_MEMORY; + } + + *pfnum = (uint16_t)ret; + return NT_STATUS_OK; +} + +/*************************************************************** + Return the smb2_hnd pointer associated with the given fnum. +***************************************************************/ + +static NTSTATUS map_fnum_to_smb2_handle(struct cli_state *cli, + uint16_t fnum, /* In */ + struct smb2_hnd **pph) /* Out */ +{ + struct idr_context *idp = cli->smb2.open_handles; + + if (idp == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + *pph = (struct smb2_hnd *)idr_find(idp, fnum); + if (*pph == NULL) { + return NT_STATUS_INVALID_HANDLE; + } + return NT_STATUS_OK; +} + +/*************************************************************** + Delete the fnum to smb2_hnd mapping. Zeros out handle on + successful return. +***************************************************************/ + +static NTSTATUS delete_smb2_handle_mapping(struct cli_state *cli, + struct smb2_hnd **pph, /* In */ + uint16_t fnum) /* In */ +{ + struct idr_context *idp = cli->smb2.open_handles; + struct smb2_hnd *ph; + + if (idp == NULL) { + return NT_STATUS_INVALID_PARAMETER; + } + + ph = (struct smb2_hnd *)idr_find(idp, fnum); + if (ph != *pph) { + return NT_STATUS_INVALID_PARAMETER; + } + idr_remove(idp, fnum); + TALLOC_FREE(*pph); + return NT_STATUS_OK; +} + +/*************************************************************** + Oplock mapping code. +***************************************************************/ + +static uint8_t flags_to_smb2_oplock(uint32_t create_flags) +{ + if (create_flags & REQUEST_BATCH_OPLOCK) { + return SMB2_OPLOCK_LEVEL_BATCH; + } else if (create_flags & REQUEST_OPLOCK) { + return SMB2_OPLOCK_LEVEL_EXCLUSIVE; + } + + /* create_flags doesn't do a level2 request. */ + return SMB2_OPLOCK_LEVEL_NONE; +} + +/*************************************************************** + Small wrapper that allows SMB2 create to return a uint16_t fnum. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_create_fnum(struct cli_state *cli, + const char *fname, + uint32_t create_flags, + uint32_t desired_access, + uint32_t file_attributes, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint16_t *pfid, + struct smb2_create_returns *cr) +{ + NTSTATUS status; + struct smb2_hnd h; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + if (cli->backup_intent) { + create_options |= FILE_OPEN_FOR_BACKUP_INTENT; + } + + /* SMB2 is pickier about pathnames. Ensure it doesn't + start in a '\' */ + if (*fname == '\\') { + fname++; + } + + status = smb2cli_create(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + fname, + flags_to_smb2_oplock(create_flags), + SMB2_IMPERSONATION_IMPERSONATION, + desired_access, + file_attributes, + share_access, + create_disposition, + create_options, + NULL, + &h.fid_persistent, + &h.fid_volatile, + cr); + + if (NT_STATUS_IS_OK(status)) { + status = map_smb2_handle_to_fnum(cli, &h, pfid); + } + + return status; +} + +/*************************************************************** + Small wrapper that allows SMB2 close to use a uint16_t fnum. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum) +{ + struct smb2_hnd *ph = NULL; + NTSTATUS status; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + status = smb2cli_close(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 0, + ph->fid_persistent, + ph->fid_volatile); + + /* Delete the fnum -> handle mapping. */ + if (NT_STATUS_IS_OK(status)) { + status = delete_smb2_handle_mapping(cli, &ph, fnum); + } + + return status; +} + +/*************************************************************** + Small wrapper that allows SMB2 to create a directory + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dname) +{ + NTSTATUS status; + uint16_t fnum; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = cli_smb2_create_fnum(cli, + dname, + 0, /* create_flags */ + FILE_READ_ATTRIBUTES, /* desired_access */ + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */ + FILE_CREATE, /* create_disposition */ + FILE_DIRECTORY_FILE, /* create_options */ + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return cli_smb2_close_fnum(cli, fnum); +} + +/*************************************************************** + Small wrapper that allows SMB2 to delete a directory + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname) +{ + NTSTATUS status; + uint16_t fnum; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = cli_smb2_create_fnum(cli, + dname, + 0, /* create_flags */ + DELETE_ACCESS, /* desired_access */ + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + FILE_DIRECTORY_FILE|FILE_DELETE_ON_CLOSE, /* create_options */ + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return cli_smb2_close_fnum(cli, fnum); +} + +/*************************************************************** + Small wrapper that allows SMB2 to unlink a pathname. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname) +{ + NTSTATUS status; + uint16_t fnum; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = cli_smb2_create_fnum(cli, + fname, + 0, /* create_flags */ + DELETE_ACCESS, /* desired_access */ + FILE_ATTRIBUTE_NORMAL, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + FILE_DELETE_ON_CLOSE, /* create_options */ + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + return cli_smb2_close_fnum(cli, fnum); +} + +/*************************************************************** + Utility function to parse a SMB2_FIND_ID_BOTH_DIRECTORY_INFO reply. +***************************************************************/ + +static NTSTATUS parse_finfo_id_both_directory_info(uint8_t *dir_data, + uint32_t dir_data_length, + struct file_info *finfo, + uint32_t *next_offset) +{ + size_t namelen = 0; + size_t slen = 0; + size_t ret = 0; + + if (dir_data_length < 4) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + *next_offset = IVAL(dir_data, 0); + + if (*next_offset > dir_data_length) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + if (*next_offset != 0) { + /* Ensure we only read what in this record. */ + dir_data_length = *next_offset; + } + + if (dir_data_length < 105) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + + finfo->atime_ts = interpret_long_date((const char *)dir_data + 16); + finfo->mtime_ts = interpret_long_date((const char *)dir_data + 24); + finfo->ctime_ts = interpret_long_date((const char *)dir_data + 32); + finfo->size = IVAL2_TO_SMB_BIG_UINT(dir_data + 40, 0); + finfo->mode = CVAL(dir_data + 56, 0); + namelen = IVAL(dir_data + 60,0); + if (namelen > (dir_data_length - 104)) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + slen = SVAL(dir_data + 68, 0); + if (slen > 24) { + return NT_STATUS_INFO_LENGTH_MISMATCH; + } + ret = pull_string_talloc(finfo, + dir_data, + FLAGS2_UNICODE_STRINGS, + &finfo->short_name, + dir_data + 70, + slen, + STR_UNICODE); + if (ret == (size_t)-1) { + /* Bad conversion. */ + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + + ret = pull_string_talloc(finfo, + dir_data, + FLAGS2_UNICODE_STRINGS, + &finfo->name, + dir_data + 104, + namelen, + STR_UNICODE); + if (ret == (size_t)-1) { + /* Bad conversion. */ + return NT_STATUS_INVALID_NETWORK_RESPONSE; + } + return NT_STATUS_OK; +} + +/******************************************************************* + Given a filename - get its directory name +********************************************************************/ + +static bool windows_parent_dirname(TALLOC_CTX *mem_ctx, + const char *dir, + char **parent, + const char **name) +{ + char *p; + ptrdiff_t len; + + p = strrchr_m(dir, '\\'); /* Find final '\\', if any */ + + if (p == NULL) { + if (!(*parent = talloc_strdup(mem_ctx, "\\"))) { + return false; + } + if (name) { + *name = dir; + } + return true; + } + + len = p-dir; + + if (!(*parent = (char *)talloc_memdup(mem_ctx, dir, len+1))) { + return false; + } + (*parent)[len] = '\0'; + + if (name) { + *name = p+1; + } + return true; +} + +/*************************************************************** + Wrapper that allows SMB2 to list a directory. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_list(struct cli_state *cli, + const char *pathname, + NTSTATUS (*fn)(const char *, + struct file_info *, + const char *, + void *), + void *state) +{ + NTSTATUS status; + uint16_t fnum = -1; + char *parent_dir = NULL; + const char *mask = NULL; + struct smb2_hnd *ph = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *subframe = NULL; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + /* Get the directory name. */ + if (!windows_parent_dirname(frame, + pathname, + &parent_dir, + &mask)) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + status = cli_smb2_create_fnum(cli, + parent_dir, + 0, /* create_flags */ + SEC_DIR_LIST|SEC_DIR_READ_ATTRIBUTE,/* desired_access */ + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE, /* share_access */ + FILE_OPEN, /* create_disposition */ + FILE_DIRECTORY_FILE, /* create_options */ + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + do { + uint8_t *dir_data = NULL; + uint32_t dir_data_length = 0; + uint32_t next_offset = 0; + subframe = talloc_stackframe(); + + status = smb2cli_query_directory(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + SMB2_FIND_ID_BOTH_DIRECTORY_INFO, + 0, /* flags */ + 0, /* file_index */ + ph->fid_persistent, + ph->fid_volatile, + mask, + 0xffff, + subframe, + &dir_data, + &dir_data_length); + + if (!NT_STATUS_IS_OK(status)) { + if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) { + break; + } + goto fail; + } + + do { + struct file_info *finfo = talloc_zero(subframe, + struct file_info); + + if (finfo == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + status = parse_finfo_id_both_directory_info(dir_data, + dir_data_length, + finfo, + &next_offset); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = fn(cli->dfs_mountpoint, + finfo, + pathname, + state); + + if (!NT_STATUS_IS_OK(status)) { + break; + } + + TALLOC_FREE(finfo); + + /* Move to next entry. */ + if (next_offset) { + dir_data += next_offset; + dir_data_length -= next_offset; + } + } while (next_offset != 0); + + TALLOC_FREE(subframe); + + } while (NT_STATUS_IS_OK(status)); + + if (NT_STATUS_EQUAL(status, STATUS_NO_MORE_FILES)) { + status = NT_STATUS_OK; + } + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + TALLOC_FREE(subframe); + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to query a path info (basic level). + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli, + const char *name, + SMB_STRUCT_STAT *sbuf, + uint32_t *attributes) +{ + NTSTATUS status; + struct smb2_create_returns cr; + uint16_t fnum = -1; + size_t namelen = strlen(name); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + /* SMB2 is pickier about pathnames. Ensure it doesn't + end in a '\' */ + if (namelen > 0 && name[namelen-1] == '\\') { + char *modname = talloc_strdup(talloc_tos(), name); + modname[namelen-1] = '\0'; + name = modname; + } + + /* This is commonly used as a 'cd'. Try qpathinfo on + a directory handle first. */ + + status = cli_smb2_create_fnum(cli, + name, + 0, /* create_flags */ + FILE_READ_ATTRIBUTES, /* desired_access */ + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + FILE_DIRECTORY_FILE, /* create_options */ + &fnum, + &cr); + + if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) { + /* Maybe a file ? */ + status = cli_smb2_create_fnum(cli, + name, + 0, /* create_flags */ + FILE_READ_ATTRIBUTES, /* desired_access */ + 0, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + 0, /* create_options */ + &fnum, + &cr); + } + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + cli_smb2_close_fnum(cli, fnum); + + ZERO_STRUCTP(sbuf); + + sbuf->st_ex_atime = nt_time_to_unix_timespec(&cr.last_access_time); + sbuf->st_ex_mtime = nt_time_to_unix_timespec(&cr.last_write_time); + sbuf->st_ex_ctime = nt_time_to_unix_timespec(&cr.change_time); + sbuf->st_ex_size = cr.end_of_file; + *attributes = cr.file_attributes; + + return NT_STATUS_OK; +} + +/*************************************************************** + Helper function for pathname operations. +***************************************************************/ + +static NTSTATUS get_fnum_from_path(struct cli_state *cli, + const char *name, + uint32_t desired_access, + uint16_t *pfnum) +{ + NTSTATUS status; + size_t namelen = strlen(name); + TALLOC_CTX *frame = talloc_stackframe(); + + /* SMB2 is pickier about pathnames. Ensure it doesn't + end in a '\' */ + if (namelen > 0 && name[namelen-1] == '\\') { + char *modname = talloc_strdup(frame, name); + if (modname == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + modname[namelen-1] = '\0'; + name = modname; + } + + /* Try to open a file handle first. */ + status = cli_smb2_create_fnum(cli, + name, + 0, /* create_flags */ + desired_access, + 0, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + 0, /* create_options */ + pfnum, + NULL); + + if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) { + status = cli_smb2_create_fnum(cli, + name, + 0, /* create_flags */ + desired_access, + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + FILE_DIRECTORY_FILE, /* create_options */ + pfnum, + NULL); + } + + fail: + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to query a path info (ALTNAME level). + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli, + const char *name, + fstring alt_name) +{ + NTSTATUS status; + DATA_BLOB outbuf = data_blob_null; + uint16_t fnum = -1; + struct smb2_hnd *ph = NULL; + uint32_t altnamelen = 0; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_READ_ATTRIBUTES, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1), + level SMB_FILE_ALTERNATE_NAME_INFORMATION (1021) == SMB2 21 */ + + status = smb2cli_query_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + (SMB_FILE_ALTERNATE_NAME_INFORMATION - 1000), /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + 0, /* in_additional_info */ + 0, /* in_flags */ + ph->fid_persistent, + ph->fid_volatile, + frame, + &outbuf); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Parse the reply. */ + if (outbuf.length < 4) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + altnamelen = IVAL(outbuf.data, 0); + if (altnamelen > outbuf.length - 4) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + if (altnamelen > 0) { + size_t ret = 0; + char *short_name = NULL; + ret = pull_string_talloc(frame, + outbuf.data, + FLAGS2_UNICODE_STRINGS, + &short_name, + outbuf.data + 4, + altnamelen, + STR_UNICODE); + if (ret == (size_t)-1) { + /* Bad conversion. */ + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + fstrcpy(alt_name, short_name); + } else { + alt_name[0] = '\0'; + } + + status = NT_STATUS_OK; + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + TALLOC_FREE(frame); + return status; +} + + +/*************************************************************** + Wrapper that allows SMB2 to query a fnum info (basic level). + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli, + uint16_t fnum, + uint16_t *mode, + off_t *size, + struct timespec *create_time, + struct timespec *access_time, + struct timespec *write_time, + struct timespec *change_time, + SMB_INO_T *ino) +{ + NTSTATUS status; + DATA_BLOB outbuf = data_blob_null; + struct smb2_hnd *ph = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1), + level 0x12 (SMB2_FILE_ALL_INFORMATION). */ + + status = smb2cli_query_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + (SMB_FILE_ALL_INFORMATION - 1000), /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + 0, /* in_additional_info */ + 0, /* in_flags */ + ph->fid_persistent, + ph->fid_volatile, + frame, + &outbuf); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Parse the reply. */ + if (outbuf.length < 0x60) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + if (create_time) { + *create_time = interpret_long_date((const char *)outbuf.data + 0x0); + } + if (access_time) { + *access_time = interpret_long_date((const char *)outbuf.data + 0x8); + } + if (write_time) { + *write_time = interpret_long_date((const char *)outbuf.data + 0x10); + } + if (change_time) { + *change_time = interpret_long_date((const char *)outbuf.data + 0x18); + } + if (mode) { + uint32_t attr = IVAL(outbuf.data, 0x20); + *mode = (uint16_t)attr; + } + if (size) { + uint64_t file_size = BVAL(outbuf.data, 0x30); + *size = (off_t)file_size; + } + if (ino) { + uint64_t file_index = BVAL(outbuf.data, 0x40); + *ino = (SMB_INO_T)file_index; + } + + fail: + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to query an fnum. + Implement on top of cli_smb2_qfileinfo_basic(). + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_getattrE(struct cli_state *cli, + uint16_t fnum, + uint16_t *attr, + off_t *size, + time_t *change_time, + time_t *access_time, + time_t *write_time) +{ + struct timespec access_time_ts; + struct timespec write_time_ts; + struct timespec change_time_ts; + NTSTATUS status = cli_smb2_qfileinfo_basic(cli, + fnum, + attr, + size, + NULL, + &access_time_ts, + &write_time_ts, + &change_time_ts, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + if (change_time) { + *change_time = change_time_ts.tv_sec; + } + if (access_time) { + *access_time = access_time_ts.tv_sec; + } + if (write_time) { + *write_time = write_time_ts.tv_sec; + } + return NT_STATUS_OK; +} + +/*************************************************************** + Wrapper that allows SMB2 to get pathname attributes. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_getatr(struct cli_state *cli, + const char *name, + uint16_t *attr, + off_t *size, + time_t *write_time) +{ + NTSTATUS status; + uint16_t fnum = -1; + struct smb2_hnd *ph = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_READ_ATTRIBUTES, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + status = cli_smb2_getattrE(cli, + fnum, + attr, + size, + NULL, + NULL, + write_time); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to query a pathname info (basic level). + Implement on top of cli_smb2_qfileinfo_basic(). + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli, + const char *name, + struct timespec *create_time, + struct timespec *access_time, + struct timespec *write_time, + struct timespec *change_time, + off_t *size, + uint16_t *mode, + SMB_INO_T *ino) +{ + NTSTATUS status; + struct smb2_hnd *ph = NULL; + uint16_t fnum = -1; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_READ_ATTRIBUTES, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = cli_smb2_qfileinfo_basic(cli, + fnum, + mode, + size, + create_time, + access_time, + write_time, + change_time, + ino); + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to query pathname streams. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli, + const char *name, + TALLOC_CTX *mem_ctx, + unsigned int *pnum_streams, + struct stream_struct **pstreams) +{ + NTSTATUS status; + struct smb2_hnd *ph = NULL; + uint16_t fnum = -1; + DATA_BLOB outbuf = data_blob_null; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_READ_ATTRIBUTES, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1), + level 22 (SMB2_FILE_STREAM_INFORMATION). */ + + status = smb2cli_query_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + (SMB_FILE_STREAM_INFORMATION - 1000), /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + 0, /* in_additional_info */ + 0, /* in_flags */ + ph->fid_persistent, + ph->fid_volatile, + frame, + &outbuf); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Parse the reply. */ + if (!parse_streams_blob(mem_ctx, + outbuf.data, + outbuf.length, + pnum_streams, + pstreams)) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to set pathname attributes. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_setatr(struct cli_state *cli, + const char *name, + uint16_t attr, + time_t mtime) +{ + NTSTATUS status; + uint16_t fnum = -1; + struct smb2_hnd *ph = NULL; + uint8_t inbuf_store[40]; + DATA_BLOB inbuf = data_blob_null; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_WRITE_ATTRIBUTES, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1), + level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */ + + inbuf.data = inbuf_store; + inbuf.length = sizeof(inbuf_store); + data_blob_clear(&inbuf); + + SIVAL(inbuf.data,32,attr); + if (mtime != 0) { + put_long_date((char *)inbuf.data + 16,mtime); + } + /* Set all the other times to -1. */ + SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL); + SBVAL(inbuf.data, 8, 0xFFFFFFFFFFFFFFFFLL); + SBVAL(inbuf.data, 24, 0xFFFFFFFFFFFFFFFFLL); + + status = smb2cli_set_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */ + &inbuf, /* in_input_buffer */ + 0, /* in_additional_info */ + ph->fid_persistent, + ph->fid_volatile); + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to set file handle times. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_setattrE(struct cli_state *cli, + uint16_t fnum, + time_t change_time, + time_t access_time, + time_t write_time) +{ + NTSTATUS status; + struct smb2_hnd *ph = NULL; + uint8_t inbuf_store[40]; + DATA_BLOB inbuf = data_blob_null; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + return NT_STATUS_INVALID_PARAMETER; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + return NT_STATUS_INVALID_PARAMETER; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + + /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1), + level 4 (SMB_FILE_BASIC_INFORMATION - 1000). */ + + inbuf.data = inbuf_store; + inbuf.length = sizeof(inbuf_store); + data_blob_clear(&inbuf); + + SBVAL(inbuf.data, 0, 0xFFFFFFFFFFFFFFFFLL); + if (change_time != 0) { + put_long_date((char *)inbuf.data + 24, change_time); + } + if (access_time != 0) { + put_long_date((char *)inbuf.data + 8, access_time); + } + if (write_time != 0) { + put_long_date((char *)inbuf.data + 16, write_time); + } + + return smb2cli_set_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + SMB_FILE_BASIC_INFORMATION - 1000, /* in_file_info_class */ + &inbuf, /* in_input_buffer */ + 0, /* in_additional_info */ + ph->fid_persistent, + ph->fid_volatile); +} + +/*************************************************************** + Wrapper that allows SMB2 to query disk attributes (size). + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail) +{ + NTSTATUS status; + uint16_t fnum = -1; + DATA_BLOB outbuf = data_blob_null; + struct smb2_hnd *ph = NULL; + uint32_t sectors_per_unit = 0; + uint32_t bytes_per_sector = 0; + uint64_t total_size = 0; + uint64_t size_free = 0; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + /* First open the top level directory. */ + status = cli_smb2_create_fnum(cli, + "", + 0, /* create_flags */ + FILE_READ_ATTRIBUTES, /* desired_access */ + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */ + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */ + FILE_OPEN, /* create_disposition */ + FILE_DIRECTORY_FILE, /* create_options */ + &fnum, + NULL); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* getinfo on the returned handle with info_type SMB2_GETINFO_FS (2), + level 3 (SMB_FS_SIZE_INFORMATION). */ + + status = smb2cli_query_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 2, /* in_info_type */ + 3, /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + 0, /* in_additional_info */ + 0, /* in_flags */ + ph->fid_persistent, + ph->fid_volatile, + frame, + &outbuf); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Parse the reply. */ + if (outbuf.length != 24) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + total_size = BVAL(outbuf.data, 0); + size_free = BVAL(outbuf.data, 8); + sectors_per_unit = IVAL(outbuf.data, 16); + bytes_per_sector = IVAL(outbuf.data, 20); + + if (bsize) { + *bsize = (int)(sectors_per_unit * bytes_per_sector); + } + if (total) { + *total = (int)total_size; + } + if (avail) { + *avail = (int)size_free; + } + + status = NT_STATUS_OK; + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to query a security descriptor. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli, + uint16_t fnum, + uint32_t sec_info, + TALLOC_CTX *mem_ctx, + struct security_descriptor **ppsd) +{ + NTSTATUS status; + DATA_BLOB outbuf = data_blob_null; + struct smb2_hnd *ph = NULL; + struct security_descriptor *lsd = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* getinfo on the returned handle with info_type SMB2_GETINFO_SEC (3) */ + + status = smb2cli_query_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 3, /* in_info_type */ + 0, /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + sec_info, /* in_additional_info */ + 0, /* in_flags */ + ph->fid_persistent, + ph->fid_volatile, + frame, + &outbuf); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Parse the reply. */ + status = unmarshall_sec_desc(mem_ctx, + outbuf.data, + outbuf.length, + &lsd); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + if (ppsd != NULL) { + *ppsd = lsd; + } else { + TALLOC_FREE(lsd); + } + + fail: + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to set a security descriptor. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli, + uint16_t fnum, + uint32_t sec_info, + const struct security_descriptor *sd) +{ + NTSTATUS status; + DATA_BLOB inbuf = data_blob_null; + struct smb2_hnd *ph = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = marshall_sec_desc(frame, + sd, + &inbuf.data, + &inbuf.length); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* setinfo on the returned handle with info_type SMB2_SETINFO_SEC (3) */ + + status = smb2cli_set_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 3, /* in_info_type */ + 0, /* in_file_info_class */ + &inbuf, /* in_input_buffer */ + sec_info, /* in_additional_info */ + ph->fid_persistent, + ph->fid_volatile); + + fail: + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to rename a file. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_rename(struct cli_state *cli, + const char *fname_src, + const char *fname_dst) +{ + NTSTATUS status; + DATA_BLOB inbuf = data_blob_null; + uint16_t fnum = -1; + struct smb2_hnd *ph = NULL; + smb_ucs2_t *converted_str = NULL; + size_t converted_size_bytes = 0; + size_t namelen = 0; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + fname_src, + DELETE_ACCESS, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* SMB2 is pickier about pathnames. Ensure it doesn't + start in a '\' */ + if (*fname_dst == '\\') { + fname_dst++; + } + + /* SMB2 is pickier about pathnames. Ensure it doesn't + end in a '\' */ + namelen = strlen(fname_dst); + if (namelen > 0 && fname_dst[namelen-1] == '\\') { + char *modname = talloc_strdup(frame, fname_dst); + modname[namelen-1] = '\0'; + fname_dst = modname; + } + + if (!push_ucs2_talloc(frame, + &converted_str, + fname_dst, + &converted_size_bytes)) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + /* W2K8 insists the dest name is not null + terminated. Remove the last 2 zero bytes + and reduce the name length. */ + + if (converted_size_bytes < 2) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + converted_size_bytes -= 2; + + inbuf = data_blob_talloc_zero(frame, + 20 + converted_size_bytes); + if (inbuf.data == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + + SIVAL(inbuf.data, 16, converted_size_bytes); + memcpy(inbuf.data + 20, converted_str, converted_size_bytes); + + /* setinfo on the returned handle with info_type SMB2_GETINFO_FILE (1), + level SMB2_FILE_RENAME_INFORMATION (SMB_FILE_RENAME_INFORMATION - 1000) */ + + status = smb2cli_set_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + SMB_FILE_RENAME_INFORMATION - 1000, /* in_file_info_class */ + &inbuf, /* in_input_buffer */ + 0, /* in_additional_info */ + ph->fid_persistent, + ph->fid_volatile); + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to set an EA on a fnum. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli, + uint16_t fnum, + const char *ea_name, + const char *ea_val, + size_t ea_len) +{ + NTSTATUS status; + DATA_BLOB inbuf = data_blob_null; + size_t bloblen = 0; + char *ea_name_ascii = NULL; + size_t namelen = 0; + struct smb2_hnd *ph = NULL; + TALLOC_CTX *frame = talloc_stackframe(); + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Marshall the SMB2 EA data. */ + if (ea_len > 0xFFFF) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (!push_ascii_talloc(frame, + &ea_name_ascii, + ea_name, + &namelen)) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (namelen < 2 || namelen > 0xFF) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + bloblen = 8 + ea_len + namelen; + /* Round up to a 4 byte boundary. */ + bloblen = ((bloblen + 3)&~3); + + inbuf = data_blob_talloc_zero(frame, bloblen); + if (inbuf.data == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + /* namelen doesn't include the NULL byte. */ + SCVAL(inbuf.data, 5, namelen - 1); + SSVAL(inbuf.data, 6, ea_len); + memcpy(inbuf.data + 8, ea_name_ascii, namelen); + memcpy(inbuf.data + 8 + namelen, ea_val, ea_len); + + /* setinfo on the handle with info_type SMB2_SETINFO_FILE (1), + level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */ + + status = smb2cli_set_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */ + &inbuf, /* in_input_buffer */ + 0, /* in_additional_info */ + ph->fid_persistent, + ph->fid_volatile); + + fail: + + TALLOC_FREE(frame); + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to set an EA on a pathname. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli, + const char *name, + const char *ea_name, + const char *ea_val, + size_t ea_len) +{ + NTSTATUS status; + uint16_t fnum = -1; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_WRITE_EA, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = cli_set_ea_fnum(cli, + fnum, + ea_name, + ea_val, + ea_len); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + fail: + + if (fnum != -1) { + cli_smb2_close_fnum(cli, fnum); + } + + return status; +} + +/*************************************************************** + Wrapper that allows SMB2 to get an EA list on a pathname. + Synchronous only. +***************************************************************/ + +NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli, + const char *name, + TALLOC_CTX *ctx, + size_t *pnum_eas, + struct ea_struct **pea_array) +{ + NTSTATUS status; + uint16_t fnum = -1; + DATA_BLOB outbuf = data_blob_null; + struct smb2_hnd *ph = NULL; + struct ea_list *ea_list = NULL; + struct ea_list *eal = NULL; + size_t ea_count = 0; + TALLOC_CTX *frame = talloc_stackframe(); + + *pnum_eas = 0; + *pea_array = NULL; + + if (smbXcli_conn_has_async_calls(cli->conn)) { + /* + * Can't use sync call while an async call is in flight + */ + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { + status = NT_STATUS_INVALID_PARAMETER; + goto fail; + } + + status = get_fnum_from_path(cli, + name, + FILE_READ_EA, + &fnum); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + status = map_fnum_to_smb2_handle(cli, + fnum, + &ph); + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* getinfo on the handle with info_type SMB2_GETINFO_FILE (1), + level 15 (SMB_FILE_FULL_EA_INFORMATION - 1000). */ + + status = smb2cli_query_info(cli->conn, + cli->timeout, + cli->smb2.session, + cli->smb2.tcon, + 1, /* in_info_type */ + SMB_FILE_FULL_EA_INFORMATION - 1000, /* in_file_info_class */ + 0xFFFF, /* in_max_output_length */ + NULL, /* in_input_buffer */ + 0, /* in_additional_info */ + 0, /* in_flags */ + ph->fid_persistent, + ph->fid_volatile, + frame, + &outbuf); + + if (!NT_STATUS_IS_OK(status)) { + goto fail; + } + + /* Parse the reply. */ + ea_list = read_nttrans_ea_list(ctx, + (const char *)outbuf.data, + outbuf.length); + if (ea_list == NULL) { + status = NT_STATUS_INVALID_NETWORK_RESPONSE; + goto fail; + } + + /* Convert to an array. */ + for (eal = ea_list; eal; eal = eal->next) { + ea_count++; + } + + if (ea_count) { + *pea_array = talloc_array(ctx, struct ea_struct, ea_count); + if (*pea_array == NULL) { + status = NT_STATUS_NO_MEMORY; + goto fail; + } + ea_count = 0; + for (eal = ea_list; eal; eal = eal->next) { + (*pea_array)[ea_count++] = ea_list->ea; + } + *pnum_eas = ea_count; + } + + fail: + + TALLOC_FREE(frame); + return status; +} + +struct cli_smb2_read_state { + struct tevent_context *ev; + struct cli_state *cli; + struct smb2_hnd *ph; + uint64_t start_offset; + uint32_t size; + uint32_t received; + uint8_t *buf; +}; + +static void cli_smb2_read_done(struct tevent_req *subreq); + +struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + off_t offset, + size_t size) +{ + NTSTATUS status; + struct tevent_req *req, *subreq; + struct cli_smb2_read_state *state; + + req = tevent_req_create(mem_ctx, &state, struct cli_smb2_read_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + state->start_offset = (uint64_t)offset; + state->size = (uint32_t)size; + state->received = 0; + state->buf = NULL; + + status = map_fnum_to_smb2_handle(cli, + fnum, + &state->ph); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + subreq = smb2cli_read_send(state, + state->ev, + state->cli->conn, + state->cli->timeout, + state->cli->smb2.session, + state->cli->smb2.tcon, + state->size, + state->start_offset, + state->ph->fid_persistent, + state->ph->fid_volatile, + 0, /* minimum_count */ + 0); /* remaining_bytes */ + + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_smb2_read_done, req); + return req; +} + +static void cli_smb2_read_done(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb2_read_state *state = tevent_req_data( + req, struct cli_smb2_read_state); + NTSTATUS status; + + status = smb2cli_read_recv(subreq, state, + &state->buf, &state->received); + if (tevent_req_nterror(req, status)) { + return; + } + + if (state->received > state->size) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + tevent_req_done(req); +} + +NTSTATUS cli_smb2_read_recv(struct tevent_req *req, + ssize_t *received, + uint8_t **rcvbuf) +{ + NTSTATUS status; + struct cli_smb2_read_state *state = tevent_req_data( + req, struct cli_smb2_read_state); + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + /* + * As in cli_read_andx_recv() rcvbuf is talloced from the request, so + * better make sure that you copy it away before you talloc_free(req). + * "rcvbuf" is NOT a talloc_ctx of its own, so do not talloc_move it! + */ + *received = (ssize_t)state->received; + *rcvbuf = state->buf; + return NT_STATUS_OK; +} + +struct cli_smb2_write_state { + struct tevent_context *ev; + struct cli_state *cli; + struct smb2_hnd *ph; + uint32_t flags; + const uint8_t *buf; + uint64_t offset; + uint32_t size; + uint32_t written; +}; + +static void cli_smb2_write_written(struct tevent_req *req); + +struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint16_t mode, + const uint8_t *buf, + off_t offset, + size_t size) +{ + NTSTATUS status; + struct tevent_req *req, *subreq = NULL; + struct cli_smb2_write_state *state = NULL; + + req = tevent_req_create(mem_ctx, &state, struct cli_smb2_write_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */ + state->flags = (uint32_t)mode; + state->buf = buf; + state->offset = (uint64_t)offset; + state->size = (uint32_t)size; + state->written = 0; + + status = map_fnum_to_smb2_handle(cli, + fnum, + &state->ph); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + subreq = smb2cli_write_send(state, + state->ev, + state->cli->conn, + state->cli->timeout, + state->cli->smb2.session, + state->cli->smb2.tcon, + state->size, + state->offset, + state->ph->fid_persistent, + state->ph->fid_volatile, + 0, /* remaining_bytes */ + state->flags, /* flags */ + state->buf); + + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_smb2_write_written, req); + return req; +} + +static void cli_smb2_write_written(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb2_write_state *state = tevent_req_data( + req, struct cli_smb2_write_state); + NTSTATUS status; + uint32_t written; + + status = smb2cli_write_recv(subreq, &written); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + state->written = written; + + tevent_req_done(req); +} + +NTSTATUS cli_smb2_write_recv(struct tevent_req *req, + size_t *pwritten) +{ + struct cli_smb2_write_state *state = tevent_req_data( + req, struct cli_smb2_write_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + tevent_req_received(req); + return status; + } + + if (pwritten != NULL) { + *pwritten = (size_t)state->written; + } + tevent_req_received(req); + return NT_STATUS_OK; +} + +/*************************************************************** + Wrapper that allows SMB2 async write using an fnum. + This is mostly cut-and-paste from Volker's code inside + source3/libsmb/clireadwrite.c, adapted for SMB2. + + Done this way so I can reuse all the logic inside cli_push() + for free :-). +***************************************************************/ + +struct cli_smb2_writeall_state { + struct tevent_context *ev; + struct cli_state *cli; + struct smb2_hnd *ph; + uint32_t flags; + const uint8_t *buf; + uint64_t offset; + uint32_t size; + uint32_t written; +}; + +static void cli_smb2_writeall_written(struct tevent_req *req); + +struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint16_t mode, + const uint8_t *buf, + off_t offset, + size_t size) +{ + NTSTATUS status; + struct tevent_req *req, *subreq = NULL; + struct cli_smb2_writeall_state *state = NULL; + uint32_t to_write; + uint32_t max_size; + bool ok; + + req = tevent_req_create(mem_ctx, &state, struct cli_smb2_writeall_state); + if (req == NULL) { + return NULL; + } + state->ev = ev; + state->cli = cli; + /* Both SMB1 and SMB2 use 1 in the following meaning write-through. */ + state->flags = (uint32_t)mode; + state->buf = buf; + state->offset = (uint64_t)offset; + state->size = (uint32_t)size; + state->written = 0; + + status = map_fnum_to_smb2_handle(cli, + fnum, + &state->ph); + if (tevent_req_nterror(req, status)) { + return tevent_req_post(req, ev); + } + + to_write = state->size; + max_size = smb2cli_conn_max_write_size(state->cli->conn); + to_write = MIN(max_size, to_write); + ok = smb2cli_conn_req_possible(state->cli->conn, &max_size); + if (ok) { + to_write = MIN(max_size, to_write); + } + + subreq = smb2cli_write_send(state, + state->ev, + state->cli->conn, + state->cli->timeout, + state->cli->smb2.session, + state->cli->smb2.tcon, + to_write, + state->offset, + state->ph->fid_persistent, + state->ph->fid_volatile, + 0, /* remaining_bytes */ + state->flags, /* flags */ + state->buf + state->written); + + if (tevent_req_nomem(subreq, req)) { + return tevent_req_post(req, ev); + } + tevent_req_set_callback(subreq, cli_smb2_writeall_written, req); + return req; +} + +static void cli_smb2_writeall_written(struct tevent_req *subreq) +{ + struct tevent_req *req = tevent_req_callback_data( + subreq, struct tevent_req); + struct cli_smb2_writeall_state *state = tevent_req_data( + req, struct cli_smb2_writeall_state); + NTSTATUS status; + uint32_t written, to_write; + uint32_t max_size; + bool ok; + + status = smb2cli_write_recv(subreq, &written); + TALLOC_FREE(subreq); + if (tevent_req_nterror(req, status)) { + return; + } + + state->written += written; + + if (state->written > state->size) { + tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); + return; + } + + to_write = state->size - state->written; + + if (to_write == 0) { + tevent_req_done(req); + return; + } + + max_size = smb2cli_conn_max_write_size(state->cli->conn); + to_write = MIN(max_size, to_write); + ok = smb2cli_conn_req_possible(state->cli->conn, &max_size); + if (ok) { + to_write = MIN(max_size, to_write); + } + + subreq = smb2cli_write_send(state, + state->ev, + state->cli->conn, + state->cli->timeout, + state->cli->smb2.session, + state->cli->smb2.tcon, + to_write, + state->offset + state->written, + state->ph->fid_persistent, + state->ph->fid_volatile, + 0, /* remaining_bytes */ + state->flags, /* flags */ + state->buf + state->written); + + if (tevent_req_nomem(subreq, req)) { + return; + } + tevent_req_set_callback(subreq, cli_smb2_writeall_written, req); +} + +NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req, + size_t *pwritten) +{ + struct cli_smb2_writeall_state *state = tevent_req_data( + req, struct cli_smb2_writeall_state); + NTSTATUS status; + + if (tevent_req_is_nterror(req, &status)) { + return status; + } + if (pwritten != NULL) { + *pwritten = (size_t)state->written; + } + return NT_STATUS_OK; +} diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h new file mode 100644 index 0000000..0068686 --- /dev/null +++ b/source3/libsmb/cli_smb2_fnum.h @@ -0,0 +1,161 @@ +/* + Unix SMB/CIFS implementation. + smb2 wrapper client routines + Copyright (C) Jeremy Allison 2013 + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef __SMB2CLI_FNUM_H__ +#define __SMB2CLI_FNUM_H__ + +struct smbXcli_conn; +struct smbXcli_session; +struct cli_state; +struct file_info; + +NTSTATUS cli_smb2_create_fnum(struct cli_state *cli, + const char *fname, + uint32_t create_flags, + uint32_t desired_access, + uint32_t file_attributes, + uint32_t share_access, + uint32_t create_disposition, + uint32_t create_options, + uint16_t *pfid, + struct smb2_create_returns *cr); + +NTSTATUS cli_smb2_close_fnum(struct cli_state *cli, uint16_t fnum); +NTSTATUS cli_smb2_mkdir(struct cli_state *cli, const char *dirname); +NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dirname); +NTSTATUS cli_smb2_unlink(struct cli_state *cli,const char *fname); +NTSTATUS cli_smb2_list(struct cli_state *cli, + const char *pathname, + NTSTATUS (*fn)(const char *, + struct file_info *, + const char *, + void *), + void *state); +NTSTATUS cli_smb2_qpathinfo_basic(struct cli_state *cli, + const char *name, + SMB_STRUCT_STAT *sbuf, + uint32_t *attributes); +NTSTATUS cli_smb2_qpathinfo_alt_name(struct cli_state *cli, + const char *name, + fstring alt_name); +NTSTATUS cli_smb2_qfileinfo_basic(struct cli_state *cli, + uint16_t fnum, + uint16_t *mode, + off_t *size, + struct timespec *create_time, + struct timespec *access_time, + struct timespec *write_time, + struct timespec *change_time, + SMB_INO_T *ino); +NTSTATUS cli_smb2_getattrE(struct cli_state *cli, + uint16_t fnum, + uint16_t *attr, + off_t *size, + time_t *change_time, + time_t *access_time, + time_t *write_time); +NTSTATUS cli_smb2_getatr(struct cli_state *cli, + const char *name, + uint16_t *attr, + off_t *size, + time_t *write_time); +NTSTATUS cli_smb2_qpathinfo2(struct cli_state *cli, + const char *fname, + struct timespec *create_time, + struct timespec *access_time, + struct timespec *write_time, + struct timespec *change_time, + off_t *size, + uint16_t *mode, + SMB_INO_T *ino); +NTSTATUS cli_smb2_qpathinfo_streams(struct cli_state *cli, + const char *name, + TALLOC_CTX *mem_ctx, + unsigned int *pnum_streams, + struct stream_struct **pstreams); +NTSTATUS cli_smb2_setatr(struct cli_state *cli, + const char *fname, + uint16_t attr, + time_t mtime); +NTSTATUS cli_smb2_setattrE(struct cli_state *cli, + uint16_t fnum, + time_t change_time, + time_t access_time, + time_t write_time); +NTSTATUS cli_smb2_dskattr(struct cli_state *cli, + int *bsize, + int *total, + int *avail); +NTSTATUS cli_smb2_query_security_descriptor(struct cli_state *cli, + uint16_t fnum, + uint32_t sec_info, + TALLOC_CTX *mem_ctx, + struct security_descriptor **ppsd); +NTSTATUS cli_smb2_set_security_descriptor(struct cli_state *cli, + uint16_t fnum, + uint32_t sec_info, + const struct security_descriptor *sd); +NTSTATUS cli_smb2_rename(struct cli_state *cli, + const char *fname_src, + const char *fname_dst); +NTSTATUS cli_smb2_set_ea_fnum(struct cli_state *cli, + uint16_t fnum, + const char *ea_name, + const char *ea_val, + size_t ea_len); +NTSTATUS cli_smb2_get_ea_list_path(struct cli_state *cli, + const char *name, + TALLOC_CTX *ctx, + size_t *pnum_eas, + struct ea_struct **pea_list); +NTSTATUS cli_smb2_set_ea_path(struct cli_state *cli, + const char *name, + const char *ea_name, + const char *ea_val, + size_t ea_len); +struct tevent_req *cli_smb2_read_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + off_t offset, + size_t size); +NTSTATUS cli_smb2_read_recv(struct tevent_req *req, + ssize_t *received, + uint8_t **rcvbuf); +struct tevent_req *cli_smb2_write_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint16_t mode, + const uint8_t *buf, + off_t offset, + size_t size); +NTSTATUS cli_smb2_write_recv(struct tevent_req *req, + size_t *pwritten); +struct tevent_req *cli_smb2_writeall_send(TALLOC_CTX *mem_ctx, + struct tevent_context *ev, + struct cli_state *cli, + uint16_t fnum, + uint16_t mode, + const uint8_t *buf, + off_t offset, + size_t size); +NTSTATUS cli_smb2_writeall_recv(struct tevent_req *req, + size_t *pwritten); +#endif /* __SMB2CLI_FNUM_H__ */ diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 77e2fa3..12a340c 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -879,11 +879,6 @@ NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname, Get the stream info ****************************************************************************/ -static bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *data, - size_t data_len, - unsigned int *pnum_streams, - struct stream_struct **pstreams); - struct cli_qpathinfo_streams_state { uint32_t num_data; uint8_t *data; @@ -986,7 +981,7 @@ NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname, return status; } -static bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata, +bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata, size_t data_len, unsigned int *pnum_streams, struct stream_struct **pstreams) diff --git a/source3/libsmb/clirap.h b/source3/libsmb/clirap.h index 91628ea..e105182 100644 --- a/source3/libsmb/clirap.h +++ b/source3/libsmb/clirap.h @@ -94,6 +94,10 @@ NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname, TALLOC_CTX *mem_ctx, unsigned int *pnum_streams, struct stream_struct **pstreams); +bool parse_streams_blob(TALLOC_CTX *mem_ctx, const uint8_t *rdata, + size_t data_len, + unsigned int *pnum_streams, + struct stream_struct **pstreams); NTSTATUS cli_qfilename(struct cli_state *cli, uint16_t fnum, TALLOC_CTX *mem_ctx, char **name); NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum, diff --git a/source3/libsmb/libsmb.h b/source3/libsmb/libsmb.h index 061f317..6df06ae 100644 --- a/source3/libsmb/libsmb.h +++ b/source3/libsmb/libsmb.h @@ -26,5 +26,6 @@ #include "client.h" #include "libads/ads_status.h" #include "libsmb/proto.h" +#include "libsmb/cli_smb2_fnum.h" #endif /* _LIBSMB_LIBSMB_H */ diff --git a/source3/wscript_build b/source3/wscript_build index 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.7.9.5 From 194edc770907a3ea7b2efc890b0dd7d36faf0d40 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 15:59:13 -0700 Subject: [PATCH 27/57] s3:libsmb: Plumb cli_smb2_rename() inside cli_rename(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit c748a959b40f184190cd537f0ad5f0772b484841) --- source3/libsmb/clifile.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 4b4e1a0..bfc3984 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1097,11 +1097,19 @@ NTSTATUS cli_rename_recv(struct tevent_req *req) NTSTATUS cli_rename(struct cli_state *cli, const char *fname_src, const char *fname_dst) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_rename(cli, + fname_src, + fname_dst); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From 6462752feafd9aa0bf8a2ca45e1b1d0a189085fb Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:00:40 -0700 Subject: [PATCH 28/57] s3:libsmb: Plumb cli_smb2_unlink() inside cli_unlink(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 179c27dd0235c4949045eef2ffb7a87175a4483b) --- source3/libsmb/clifile.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index bfc3984..f2e4ac2 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1415,11 +1415,17 @@ NTSTATUS cli_unlink_recv(struct tevent_req *req) NTSTATUS cli_unlink(struct cli_state *cli, const char *fname, uint16_t mayhave_attrs) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_unlink(cli, fname); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From 04c17cd645196cc43d73078019269dae64be26c8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:01:49 -0700 Subject: [PATCH 29/57] s3:libsmb: Plumb cli_smb2_mkdir() inside cli_mkdir(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 46da267afd540fe2d31f1395cda9e2853cf6432a) --- source3/libsmb/clifile.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index f2e4ac2..9659fc1 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1525,11 +1525,17 @@ NTSTATUS cli_mkdir_recv(struct tevent_req *req) NTSTATUS cli_mkdir(struct cli_state *cli, const char *dname) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_mkdir(cli, dname); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From 08cb0080eed01e0c1bb2557120e7d3df8e9b1c1f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:03:00 -0700 Subject: [PATCH 30/57] s3:libsmb: Plumb cli_smb2_rmdir() inside cli_rmdir(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 04d396566b90f32dc239450596ab50502f9cbb02) --- source3/libsmb/clifile.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 9659fc1..d63734d 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1635,11 +1635,17 @@ NTSTATUS cli_rmdir_recv(struct tevent_req *req) NTSTATUS cli_rmdir(struct cli_state *cli, const char *dname) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_rmdir(cli, dname); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From deeb6fff172a28ad5bcaf98f1fe9c690b8db331d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:06:19 -0700 Subject: [PATCH 31/57] s3:libsmb: Plumb cli_smb2_create_fnum() inside cli_ntcreate(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit c1c4491d5e5bb16c274fe4fe162156a7ec910b93) --- source3/libsmb/clifile.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index d63734d..3c799a6 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -1914,11 +1914,26 @@ NTSTATUS cli_ntcreate(struct cli_state *cli, uint8_t SecurityFlags, uint16_t *pfid) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_create_fnum(cli, + fname, + CreatFlags, + DesiredAccess, + FileAttributes, + ShareAccess, + CreateDisposition, + CreateOptions, + pfid, + NULL); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From f5dc4f193deb33a9bc4d065ac5407bed44a9c47d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:10:34 -0700 Subject: [PATCH 32/57] s3:libsmb: Plumb cli_smb2_close_fnum() inside cli_close(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 85f60cc3d8f68ce5eb687cc6e367bb66bdef8b99) --- source3/libsmb/clifile.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 3c799a6..571e1cc 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -2536,11 +2536,17 @@ NTSTATUS cli_close_recv(struct tevent_req *req) NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_close_fnum(cli, fnum); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From ec7b4f14405d562ea737192dc22032028b375211 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:11:59 -0700 Subject: [PATCH 33/57] s3:libsmb: Plumb cli_smb2_getattrE() inside cli_getattrE(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 0bbc0446210fa504f9834de948c4d066df752666) --- source3/libsmb/clifile.c | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 571e1cc..e3fb62d 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -3379,11 +3379,23 @@ NTSTATUS cli_getattrE(struct cli_state *cli, time_t *access_time, time_t *write_time) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev = NULL; struct tevent_req *req = NULL; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_getattrE(cli, + fnum, + attr, + size, + change_time, + access_time, + write_time); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From 424dadf24144948b273d7d8bf07ddbf7d02099f0 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:14:47 -0700 Subject: [PATCH 34/57] s3:libsmb: Plumb cli_smb2_setattrE() inside cli_setattrE(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 83c410c99e3ef8db00dd002c1a1a93b0035cd2e7) --- source3/libsmb/clifile.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index e3fb62d..d0e9bb6 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -3647,11 +3647,21 @@ NTSTATUS cli_setattrE(struct cli_state *cli, time_t access_time, time_t write_time) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev = NULL; struct tevent_req *req = NULL; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_setattrE(cli, + fnum, + change_time, + access_time, + write_time); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From 795635cce3f6cc8430523fd487a5b6cd022aca64 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:16:03 -0700 Subject: [PATCH 35/57] s3:libsmb: Plumb cli_smb2_setatr() inside cli_setatr(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit ea267a7e4b4c413336b2bf54eb53ffc8d1524b44) --- source3/libsmb/clifile.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index d0e9bb6..4ac7313 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -3786,11 +3786,20 @@ NTSTATUS cli_setatr(struct cli_state *cli, uint16_t attr, time_t mtime) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev = NULL; struct tevent_req *req = NULL; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_setatr(cli, + fname, + attr, + mtime); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From 99399b754ceb51f926cb7240b85a438f5dccfc47 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 14 Aug 2013 14:37:11 -0700 Subject: [PATCH 36/57] s3:libsmb: Plumb cli_smb2_getatr() inside cli_getatr(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 75d2e18502ccb811c018535f3c5c7325bdf5e613) --- source3/libsmb/clifile.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 4ac7313..f674118 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -3538,11 +3538,21 @@ NTSTATUS cli_getatr(struct cli_state *cli, off_t *size, time_t *write_time) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev = NULL; struct tevent_req *req = NULL; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_getatr(cli, + fname, + attr, + size, + write_time); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From 674ec2d995df833448b12c1414b8e27768d13166 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:17:12 -0700 Subject: [PATCH 37/57] s3:libsmb: Plumb cli_smb2_dskattr() inside cli_dskattr(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit c6ed0b88312d7e231749a09a87944caea4c9808e) --- source3/libsmb/clifile.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index f674118..77796d8 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -4034,11 +4034,17 @@ NTSTATUS cli_dskattr_recv(struct tevent_req *req, int *bsize, int *total, int *a NTSTATUS cli_dskattr(struct cli_state *cli, int *bsize, int *total, int *avail) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev = NULL; struct tevent_req *req = NULL; NTSTATUS status = NT_STATUS_OK; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_dskattr(cli, bsize, total, avail); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From 68d79dfb92b6dbc234a604ea1e5a885cc5d807c3 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:19:06 -0700 Subject: [PATCH 38/57] s3:libsmb: Fix cli_set_ea_path() to use frame instead of talloc_tos(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit c1aeada4dd1f165eb33354c5a4323ed1ebf453a9) --- source3/libsmb/clifile.c | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 77796d8..5cd1ff2 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -4322,9 +4322,10 @@ NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path, NTSTATUS status; TALLOC_CTX *frame = talloc_stackframe(); - param = talloc_array(talloc_tos(), uint8_t, 6); + param = talloc_array(frame, uint8_t, 6); if (!param) { - return NT_STATUS_NO_MEMORY; + status = NT_STATUS_NO_MEMORY; + goto fail; } SSVAL(param,0,SMB_INFO_SET_EA); SSVAL(param,2,0); @@ -4337,7 +4338,10 @@ NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path, status = cli_set_ea(cli, TRANSACT2_SETPATHINFO, param, param_len, ea_name, ea_val, ea_len); - talloc_free(frame); + + fail: + + TALLOC_FREE(frame); return status; } -- 1.7.9.5 From ac8cb980aa70eb75afb16934c64d91c4e21a5684 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:21:48 -0700 Subject: [PATCH 39/57] s3:libsmb: Plumb cli_smb2_set_ea_path() inside cli_set_ea_path(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 3276853e59c2686873baad7c6f9d2665ed6fdd56) --- source3/libsmb/clifile.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 5cd1ff2..2cfe7cd 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -4320,7 +4320,17 @@ NTSTATUS cli_set_ea_path(struct cli_state *cli, const char *path, unsigned int param_len = 0; uint8_t *param; NTSTATUS status; - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; + + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_set_ea_path(cli, + path, + ea_name, + ea_val, + ea_len); + } + + frame = talloc_stackframe(); param = talloc_array(frame, uint8_t, 6); if (!param) { -- 1.7.9.5 From f2c5239ad21fc9584afcbcccc20c27c6f9987708 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:32:55 -0700 Subject: [PATCH 40/57] s3:libsmb: Plumb cli_smb2_set_ea_fnum() inside cli_set_ea_fnum(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit f8dfc50124e5b5083aa801d9658389dd3fa6698a) --- source3/libsmb/clifile.c | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index 2cfe7cd..d186112 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -4365,6 +4365,14 @@ NTSTATUS cli_set_ea_fnum(struct cli_state *cli, uint16_t fnum, { uint8_t param[6]; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_set_ea_fnum(cli, + fnum, + ea_name, + ea_val, + ea_len); + } + memset(param, 0, 6); SSVAL(param,0,fnum); SSVAL(param,2,SMB_INFO_SET_EA); -- 1.7.9.5 From 5188a6e8889ddcc7d8f6a0f32061aa1f931d21d1 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:42:02 -0700 Subject: [PATCH 41/57] s3:libsmb: Plumb cli_smb2_get_ea_list_path() inside cli_get_ea_list_path(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 7e2d969deb1d4bcf3add422d80852b2d386cfaac) --- source3/libsmb/clifile.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c index d186112..424354b 100644 --- a/source3/libsmb/clifile.c +++ b/source3/libsmb/clifile.c @@ -4554,11 +4554,21 @@ NTSTATUS cli_get_ea_list_path(struct cli_state *cli, const char *path, size_t *pnum_eas, struct ea_struct **pea_list) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev = NULL; struct tevent_req *req = NULL; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_get_ea_list_path(cli, + path, + ctx, + pnum_eas, + pea_list); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From d839ebdd064f146f088e5632346e7e4268b6b3ce Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:43:33 -0700 Subject: [PATCH 42/57] s3:libsmb: Plumb cli_smb2_list() inside cli_list(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 73255d3ba912b3a112f9d766deae895f51e16cd9) --- source3/libsmb/clilist.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c index b0d3a4e..ed970cd 100644 --- a/source3/libsmb/clilist.c +++ b/source3/libsmb/clilist.c @@ -933,7 +933,7 @@ NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16 attribute, NTSTATUS (*fn)(const char *, struct file_info *, const char *, void *), void *state) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; @@ -941,6 +941,12 @@ NTSTATUS cli_list(struct cli_state *cli, const char *mask, uint16 attribute, size_t i, num_finfo; uint16_t info_level; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_list(cli, mask, fn, state); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From 1415c0f9544f66d2fd2493de557fe8ac645b8930 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:45:05 -0700 Subject: [PATCH 43/57] s3:libsmb: Plumb cli_smb2_qpathinfo2() inside cli_qpathinfo2(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit f2f566b1cc8d55bd1cf93478b877a3e7f455855c) --- source3/libsmb/clirap.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 12a340c..41608dd 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -845,11 +845,25 @@ NTSTATUS cli_qpathinfo2(struct cli_state *cli, const char *fname, off_t *size, uint16 *mode, SMB_INO_T *ino) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_qpathinfo2(cli, + fname, + create_time, + access_time, + write_time, + change_time, + size, + mode, + ino); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From c55396516b96926cf18e69536b42cdbac92d18d4 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:46:05 -0700 Subject: [PATCH 44/57] s3:libsmb: Plumb cli_smb2_qpathinfo_streams() inside cli_qpathinfo_streams(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit e96309ca1b057d430444531523bb2c9f59fcd624) --- source3/libsmb/clirap.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 41608dd..bb4f334 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -965,11 +965,21 @@ NTSTATUS cli_qpathinfo_streams(struct cli_state *cli, const char *fname, unsigned int *pnum_streams, struct stream_struct **pstreams) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_qpathinfo_streams(cli, + fname, + mem_ctx, + pnum_streams, + pstreams); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From 9be3ae4fc5ad1c3659531403428ef99bdacd468f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:47:21 -0700 Subject: [PATCH 45/57] s3:libsmb: Plumb cli_smb2_qfileinfo_basic() inside cli_qfileinfo_basic(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 2bb3e251d59910d9bf527a73271094702bceefe2) --- source3/libsmb/clirap.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index bb4f334..06dea82 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -1149,6 +1149,18 @@ NTSTATUS cli_qfileinfo_basic(struct cli_state *cli, uint16_t fnum, uint32_t num_rdata; NTSTATUS status; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_qfileinfo_basic(cli, + fnum, + mode, + size, + create_time, + access_time, + write_time, + change_time, + ino); + } + /* if its a win95 server then fail this - win95 totally screws it up */ if (cli->win95) { -- 1.7.9.5 From 0bf83c88be3824c402a08129e2dcb3fe4d0dd8c8 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 10:52:02 -0700 Subject: [PATCH 46/57] s3:libsmb: Plumb cli_smb2_qpathinfo_basic() inside cli_qpathinfo_basic(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit cba3ed0466b8598e28a44809778b99e97b1bf1a1) --- source3/libsmb/clirap.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 06dea82..7a480d6 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -1275,11 +1275,20 @@ NTSTATUS cli_qpathinfo_basic_recv(struct tevent_req *req, NTSTATUS cli_qpathinfo_basic(struct cli_state *cli, const char *name, SMB_STRUCT_STAT *sbuf, uint32 *attributes) { - TALLOC_CTX *frame = talloc_stackframe(); + TALLOC_CTX *frame = NULL; struct tevent_context *ev; struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_qpathinfo_basic(cli, + name, + sbuf, + attributes); + } + + frame = talloc_stackframe(); + if (smbXcli_conn_has_async_calls(cli->conn)) { /* * Can't use sync call while an async call is in flight -- 1.7.9.5 From fbe9f3258d5ade4fa4338a45128928844b5cddfb Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Wed, 7 Aug 2013 16:50:03 -0700 Subject: [PATCH 47/57] s3:libsmb: Plumb cli_smb2_qpathinfo_alt_name() inside cli_qpathinfo_alt_name(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit de895bf228432f2a42bcdcadcf12ffd1be64022f) --- source3/libsmb/clirap.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c index 7a480d6..d6d2fae 100644 --- a/source3/libsmb/clirap.c +++ b/source3/libsmb/clirap.c @@ -1326,6 +1326,12 @@ NTSTATUS cli_qpathinfo_alt_name(struct cli_state *cli, const char *fname, fstrin size_t converted_size = 0; NTSTATUS status; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_qpathinfo_alt_name(cli, + fname, + alt_name); + } + status = cli_qpathinfo(talloc_tos(), cli, fname, SMB_QUERY_FILE_ALT_NAME_INFO, 4, CLI_BUFFER_SIZE, &rdata, &num_rdata); -- 1.7.9.5 From a5f92614aa5636b7ec27f9a0c28b0e709a6b30f2 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 11:00:08 -0700 Subject: [PATCH 48/57] s3:libsmb: Plumb cli_smb2_query_security_descriptor() inside cli_query_security_descriptor(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 1db7e90451f31d75298508c19a859d98d56d7e7c) --- source3/libsmb/clisecdesc.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/source3/libsmb/clisecdesc.c b/source3/libsmb/clisecdesc.c index 24da39d..a82feab 100644 --- a/source3/libsmb/clisecdesc.c +++ b/source3/libsmb/clisecdesc.c @@ -20,6 +20,7 @@ #include "includes.h" #include "libsmb/libsmb.h" #include "../libcli/security/secdesc.h" +#include "../libcli/smb/smbXcli_base.h" NTSTATUS cli_query_security_descriptor(struct cli_state *cli, uint16_t fnum, @@ -33,6 +34,14 @@ NTSTATUS cli_query_security_descriptor(struct cli_state *cli, NTSTATUS status; struct security_descriptor *lsd; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_query_security_descriptor(cli, + fnum, + sec_info, + mem_ctx, + sd); + } + SIVAL(param, 0, fnum); SIVAL(param, 4, sec_info); -- 1.7.9.5 From 85df78206643f67ca599173036e2220bd389a46f Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Thu, 8 Aug 2013 11:00:49 -0700 Subject: [PATCH 49/57] s3:libsmb: Plumb cli_smb2_set_security_descriptor() inside cli_set_security_descriptor(). Signed-off-by: Jeremy Allison Reviewed-by: Stefan Metzmacher (cherry picked from commit 80758e4b07c87280e778ba161c2c9c4a2ee47853) --- source3/libsmb/clisecdesc.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/source3/libsmb/clisecdesc.c b/source3/libsmb/clisecdesc.c index a82feab..986610f 100644 --- a/source3/libsmb/clisecdesc.c +++ b/source3/libsmb/clisecdesc.c @@ -104,6 +104,13 @@ NTSTATUS cli_set_security_descriptor(struct cli_state *cli, size_t len; NTSTATUS status; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return cli_smb2_set_security_descriptor(cli, + fnum, + sec_info, + sd); + } + status = marshall_sec_desc(talloc_tos(), sd, &data, &len); if (!NT_STATUS_IS_OK(status)) { DEBUG(10, ("marshall_sec_desc failed: %s\n", -- 1.7.9.5 From 66cc4267cbc397d2b9af33491d27e78fc836c259 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 16:33:30 +0200 Subject: [PATCH 50/57] s3:libsmb: add SMB2 support to cli_push* Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 6896bf0b28a07eb8ead5b3bd2bc50229aa59d439) --- source3/libsmb/clireadwrite.c | 66 +++++++++++++++++++++++++++++++---------- 1 file changed, 50 insertions(+), 16 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 10dc79b..821bcb1 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -1120,7 +1120,11 @@ struct tevent_req *cli_push_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, state->priv = priv; state->next_offset = start_offset; - state->chunk_size = cli_write_max_bufsize(cli, mode, 14); + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + state->chunk_size = smb2cli_conn_max_write_size(cli->conn); + } else { + state->chunk_size = cli_write_max_bufsize(cli, mode, 14); + } if (state->chunk_size > page_size) { state->chunk_size &= ~(page_size - 1); } @@ -1257,21 +1261,47 @@ static void cli_push_chunk_ship(struct cli_push_chunk *chunk) ofs = chunk->ofs + chunk->tmp_size; size = chunk->total_size - chunk->tmp_size; - ok = smb1cli_conn_req_possible(state->cli->conn); - if (!ok) { - return; - } + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + uint32_t max_size; - chunk->subreq = cli_write_andx_send(chunk, - state->ev, - state->cli, - state->fnum, - state->mode, - buf, - ofs, - size); - if (tevent_req_nomem(chunk->subreq, req)) { - return; + ok = smb2cli_conn_req_possible(state->cli->conn, &max_size); + if (!ok) { + return; + } + + /* + * downgrade depending on the available credits + */ + size = MIN(max_size, size); + + chunk->subreq = cli_smb2_write_send(chunk, + state->ev, + state->cli, + state->fnum, + state->mode, + buf, + ofs, + size); + if (tevent_req_nomem(chunk->subreq, req)) { + return; + } + } else { + ok = smb1cli_conn_req_possible(state->cli->conn); + if (!ok) { + return; + } + + chunk->subreq = cli_write_andx_send(chunk, + state->ev, + state->cli, + state->fnum, + state->mode, + buf, + ofs, + size); + if (tevent_req_nomem(chunk->subreq, req)) { + return; + } } tevent_req_set_callback(chunk->subreq, cli_push_chunk_done, @@ -1296,7 +1326,11 @@ static void cli_push_chunk_done(struct tevent_req *subreq) chunk->subreq = NULL; - status = cli_write_andx_recv(subreq, &written); + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + status = cli_smb2_write_recv(subreq, &written); + } else { + status = cli_write_andx_recv(subreq, &written); + } TALLOC_FREE(subreq); if (tevent_req_nterror(req, status)) { return; -- 1.7.9.5 From 73753e144469a2ec840670e6a94808b79edbe28f Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 18:20:08 +0200 Subject: [PATCH 51/57] s3:libsmb: add SMB2 support to cli_pull* Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit a85d4511e6bc84938d60f090b44a5b1468ee4136) --- source3/libsmb/clireadwrite.c | 60 +++++++++++++++++++++++++++++++---------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index 821bcb1..d28c226 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -360,7 +360,11 @@ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, return tevent_req_post(req, ev); } - state->chunk_size = cli_read_max_bufsize(cli); + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + state->chunk_size = smb2cli_conn_max_read_size(cli->conn); + } else { + state->chunk_size = cli_read_max_bufsize(cli); + } if (state->chunk_size > page_size) { state->chunk_size &= ~(page_size - 1); } @@ -519,19 +523,43 @@ static void cli_pull_chunk_ship(struct cli_pull_chunk *chunk) ofs = chunk->ofs + chunk->tmp_size; size = chunk->total_size - chunk->tmp_size; - ok = smb1cli_conn_req_possible(state->cli->conn); - if (!ok) { - return; - } + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + uint32_t max_size; - chunk->subreq = cli_read_andx_send(chunk, - state->ev, - state->cli, - state->fnum, - ofs, - size); - if (tevent_req_nomem(chunk->subreq, req)) { - return; + ok = smb2cli_conn_req_possible(state->cli->conn, &max_size); + if (!ok) { + return; + } + + /* + * downgrade depending on the available credits + */ + size = MIN(max_size, size); + + chunk->subreq = cli_smb2_read_send(chunk, + state->ev, + state->cli, + state->fnum, + ofs, + size); + if (tevent_req_nomem(chunk->subreq, req)) { + return; + } + } else { + ok = smb1cli_conn_req_possible(state->cli->conn); + if (!ok) { + return; + } + + chunk->subreq = cli_read_andx_send(chunk, + state->ev, + state->cli, + state->fnum, + ofs, + size); + if (tevent_req_nomem(chunk->subreq, req)) { + return; + } } tevent_req_set_callback(chunk->subreq, cli_pull_chunk_done, @@ -557,7 +585,11 @@ static void cli_pull_chunk_done(struct tevent_req *subreq) chunk->subreq = NULL; - status = cli_read_andx_recv(subreq, &received, &buf); + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { + status = cli_smb2_read_recv(subreq, &received, &buf); + } else { + status = cli_read_andx_recv(subreq, &received, &buf); + } if (NT_STATUS_EQUAL(status, NT_STATUS_END_OF_FILE)) { received = 0; status = NT_STATUS_OK; -- 1.7.9.5 From 044cb3becf763fb8e513f0a6a854f69ebcf39392 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Tue, 13 Aug 2013 18:38:57 +0200 Subject: [PATCH 52/57] s3:libsmb: add support for SMB2 in cli_writeall() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit ccf7b3719121e03ed06d15b9af5373eecba3e828) --- source3/libsmb/clireadwrite.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/source3/libsmb/clireadwrite.c b/source3/libsmb/clireadwrite.c index d28c226..adcd98b 100644 --- a/source3/libsmb/clireadwrite.c +++ b/source3/libsmb/clireadwrite.c @@ -1066,7 +1066,13 @@ NTSTATUS cli_writeall(struct cli_state *cli, uint16_t fnum, uint16_t mode, if (ev == NULL) { goto fail; } - req = cli_writeall_send(frame, ev, cli, fnum, mode, buf, offset, size); + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + req = cli_smb2_writeall_send(frame, ev, cli, fnum, mode, + buf, offset, size); + } else { + req = cli_writeall_send(frame, ev, cli, fnum, mode, + buf, offset, size); + } if (req == NULL) { goto fail; } @@ -1074,7 +1080,11 @@ NTSTATUS cli_writeall(struct cli_state *cli, uint16_t fnum, uint16_t mode, status = map_nt_error_from_unix(errno); goto fail; } - status = cli_writeall_recv(req, pwritten); + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + status = cli_smb2_writeall_recv(req, pwritten); + } else { + status = cli_writeall_recv(req, pwritten); + } fail: TALLOC_FREE(frame); return status; -- 1.7.9.5 From 426497ffe18b376a72509238dcc38ee7ecd44662 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 11:38:22 +0200 Subject: [PATCH 53/57] s3:libsmb: make cli_tdis_send/recv static Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 80d4f64352c0ddacb9ee15d2b48a42a0b7929501) --- source3/libsmb/cliconnect.c | 4 ++-- source3/libsmb/proto.h | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index d74ea0e..98b3bf1 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2757,7 +2757,7 @@ struct cli_tdis_state { static void cli_tdis_done(struct tevent_req *subreq); -struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx, +static struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli) { @@ -2796,7 +2796,7 @@ static void cli_tdis_done(struct tevent_req *subreq) tevent_req_done(req); } -NTSTATUS cli_tdis_recv(struct tevent_req *req) +static NTSTATUS cli_tdis_recv(struct tevent_req *req) { return tevent_req_simple_recv_ntstatus(req); } diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index 48496c8..648bdda 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -75,10 +75,6 @@ NTSTATUS cli_tcon_andx(struct cli_state *cli, const char *share, const char *dev, const char *pass, int passlen); NTSTATUS cli_tree_connect(struct cli_state *cli, const char *share, const char *dev, const char *pass, int passlen); -struct tevent_req *cli_tdis_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct cli_state *cli); -NTSTATUS cli_tdis_recv(struct tevent_req *req); NTSTATUS cli_tdis(struct cli_state *cli); NTSTATUS cli_connect_nb(const char *host, const struct sockaddr_storage *dest_ss, uint16_t port, int name_type, const char *myname, -- 1.7.9.5 From 35dea645add3c27244177150a49767e416cc0f46 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 11:44:10 +0200 Subject: [PATCH 54/57] s3:libsmb: only set tcon to invalid in smb2cli_tdis* This matches the behavior of cli_tdis*. Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit d732e9aab3bbad3ea97f8b120e57b41152aaee3b) --- source3/libsmb/smb2cli_tcon.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/source3/libsmb/smb2cli_tcon.c b/source3/libsmb/smb2cli_tcon.c index b3136fa..2467ce5 100644 --- a/source3/libsmb/smb2cli_tcon.c +++ b/source3/libsmb/smb2cli_tcon.c @@ -243,7 +243,8 @@ static void smb2cli_tdis_done(struct tevent_req *subreq) if (tevent_req_nterror(req, status)) { return; } - TALLOC_FREE(state->cli->smb2.tcon); + smb2cli_tcon_set_values(state->cli->smb2.tcon, NULL, + UINT32_MAX, 0, 0, 0, 0); tevent_req_done(req); } -- 1.7.9.5 From cd7d8bbbf51d521eb72c57945041212379c4dd02 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 11:44:58 +0200 Subject: [PATCH 55/57] s3:libsmb: call smb2cli_tdis() from cli_tdis() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit e6be68fb5e4dc528f7365f3413b9b66090992f42) --- source3/libsmb/cliconnect.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 98b3bf1..0e5f8a9 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2807,6 +2807,10 @@ NTSTATUS cli_tdis(struct cli_state *cli) struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + return smb2cli_tdis(cli); + } + if (smbXcli_conn_has_async_calls(cli->conn)) { return NT_STATUS_INVALID_PARAMETER; } -- 1.7.9.5 From 339636d7ad7e0b18f3a54b1a8ff60ffe1464dd02 Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 11:48:40 +0200 Subject: [PATCH 56/57] s3:libsmb: make cli_ulogoff_send/recv static Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison (cherry picked from commit 1d7bdfc4feac35d92b003c3c78f502897ecc5d4e) --- source3/libsmb/cliconnect.c | 4 ++-- source3/libsmb/proto.h | 4 ---- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index 0e5f8a9..f64f37e 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2245,7 +2245,7 @@ struct cli_ulogoff_state { static void cli_ulogoff_done(struct tevent_req *subreq); -struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx, +static struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli) { @@ -2288,7 +2288,7 @@ static void cli_ulogoff_done(struct tevent_req *subreq) tevent_req_done(req); } -NTSTATUS cli_ulogoff_recv(struct tevent_req *req) +static NTSTATUS cli_ulogoff_recv(struct tevent_req *req) { return tevent_req_simple_recv_ntstatus(req); } diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h index 648bdda..a1389ff 100644 --- a/source3/libsmb/proto.h +++ b/source3/libsmb/proto.h @@ -54,10 +54,6 @@ struct tevent_req *cli_session_setup_guest_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev, struct cli_state *cli); NTSTATUS cli_session_setup_guest_recv(struct tevent_req *req); -struct tevent_req *cli_ulogoff_send(TALLOC_CTX *mem_ctx, - struct tevent_context *ev, - struct cli_state *cli); -NTSTATUS cli_ulogoff_recv(struct tevent_req *req); NTSTATUS cli_ulogoff(struct cli_state *cli); struct tevent_req *cli_tcon_andx_create(TALLOC_CTX *mem_ctx, struct tevent_context *ev, -- 1.7.9.5 From 98b3da44f057bfa6c29eadf9be4dbe3e2ad1cf5c Mon Sep 17 00:00:00 2001 From: Stefan Metzmacher Date: Wed, 14 Aug 2013 15:18:47 -0700 Subject: [PATCH 57/57] s3:libsmb: call smb2cli_logoff() from cli_ulogoff() Signed-off-by: Stefan Metzmacher Reviewed-by: Jeremy Allison Autobuild-User(master): Stefan Metzmacher Autobuild-Date(master): Thu Aug 15 10:53:21 CEST 2013 on sn-devel-104 (cherry picked from commit b706ca6e55aa76d4da901c69d991969602facc3b) --- source3/libsmb/cliconnect.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/source3/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c index f64f37e..7ec3b56 100644 --- a/source3/libsmb/cliconnect.c +++ b/source3/libsmb/cliconnect.c @@ -2299,6 +2299,18 @@ NTSTATUS cli_ulogoff(struct cli_state *cli) struct tevent_req *req; NTSTATUS status = NT_STATUS_NO_MEMORY; + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { + status = smb2cli_logoff(cli->conn, + cli->timeout, + cli->smb2.session); + if (!NT_STATUS_IS_OK(status)) { + return status; + } + smb2cli_session_set_id_and_flags(cli->smb2.session, + UINT64_MAX, 0); + return NT_STATUS_OK; + } + if (smbXcli_conn_has_async_calls(cli->conn)) { return NT_STATUS_INVALID_PARAMETER; } -- 1.7.9.5