The Samba-Bugzilla – Attachment 9014 Details for
Bug 9974
smbclient does not support SMB2
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
initial git-am patch for 4.1.x
0001-Test-patch-adding-SMB2-support-to-smbclient-and-smbc.patch (text/plain), 93.24 KB, created by
Jeremy Allison
on 2013-07-02 20:06:47 UTC
(
hide
)
Description:
initial git-am patch for 4.1.x
Filename:
MIME Type:
Creator:
Jeremy Allison
Created:
2013-07-02 20:06:47 UTC
Size:
93.24 KB
patch
obsolete
>From 030a6e7805241c172b4b7c70ad5e1248960e334b Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 2 Jul 2013 12:46:23 -0700 >Subject: [PATCH] Test patch adding SMB2 support to smbclient and smbcacls. > >To be broken up into a set of micro-patches for official review. > >Signed-off-by: Jeremy Allison <jra@samba.org> >--- > lib/param/param_table.c | 2 +- > libcli/smb/smb2_create_blob.h | 12 + > libcli/smb/smb2cli_create.c | 39 +- > libcli/smb/smb2cli_write.c | 28 +- > libcli/smb/smbXcli_base.c | 5 +- > libcli/smb/smbXcli_base.h | 13 +- > source3/include/client.h | 1 + > source3/include/includes.h | 4 +- > source3/include/proto.h | 4 + > source3/lib/util.c | 25 +- > source3/libsmb/cli_np_tstream.c | 10 +- > source3/libsmb/cliconnect.c | 6 +- > source3/libsmb/clifile.c | 105 ++- > source3/libsmb/clilist.c | 10 +- > source3/libsmb/clirap.c | 66 +- > source3/libsmb/clirap.h | 4 + > source3/libsmb/clireadwrite.c | 83 +- > source3/libsmb/clisecdesc.c | 18 + > source3/libsmb/smb2cli_fnum.c | 1843 +++++++++++++++++++++++++++++++++++++++ > source3/libsmb/smb2cli_fnum.h | 131 +++ > source3/libsmb/smb2cli_tcon.c | 1 + > source3/param/loadparm.c | 9 +- > source3/torture/test_smb2.c | 62 +- > source3/utils/smbcacls.c | 4 + > source3/wscript_build | 1 + > 25 files changed, 2372 insertions(+), 114 deletions(-) > create mode 100644 source3/libsmb/smb2cli_fnum.c > create mode 100644 source3/libsmb/smb2cli_fnum.h > >diff --git a/lib/param/param_table.c b/lib/param/param_table.c >index 1b1497c..3d6ddbb 100644 >--- a/lib/param/param_table.c >+++ b/lib/param/param_table.c >@@ -27,7 +27,7 @@ > along with this program. If not, see <http://www.gnu.org/licenses/>. > */ > >-static const struct enum_list enum_protocol[] = { >+const struct enum_list enum_protocol[] = { > {PROTOCOL_SMB2_10, "SMB2"}, /* for now keep PROTOCOL_SMB2_10 */ > {PROTOCOL_SMB3_00, "SMB3"}, /* for now keep PROTOCOL_SMB3_00 */ > {PROTOCOL_SMB3_00, "SMB3_00"}, >diff --git a/libcli/smb/smb2_create_blob.h b/libcli/smb/smb2_create_blob.h >index 008befe..a87d36d 100644 >--- a/libcli/smb/smb2_create_blob.h >+++ b/libcli/smb/smb2_create_blob.h >@@ -23,6 +23,18 @@ > #ifndef _LIBCLI_SMB_SMB2_CREATE_BLOB_H_ > #define _LIBCLI_SMB_SMB2_CREATE_BLOB_H_ > >+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; >+}; >+ > struct smb2_create_blob { > const char *tag; > DATA_BLOB data; >diff --git a/libcli/smb/smb2cli_create.c b/libcli/smb/smb2cli_create.c >index 627bdcb..462b30d 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/smb2cli_write.c b/libcli/smb/smb2cli_write.c >index 8e65460..36a4d77 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,30 @@ 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)) { >+ return status; >+ } >+ if (written) { >+ *written = state->written; >+ } >+ return NT_STATUS_OK; > } > > NTSTATUS smb2cli_write(struct smbXcli_conn *conn, >@@ -126,7 +143,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 +173,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.c b/libcli/smb/smbXcli_base.c >index 5a5828a..0b020fd 100644 >--- a/libcli/smb/smbXcli_base.c >+++ b/libcli/smb/smbXcli_base.c >@@ -450,7 +450,7 @@ uint16_t smbXcli_conn_max_requests(struct smbXcli_conn *conn) > /* > * TODO... > */ >- return 1; >+ return 32; > } > > return conn->smb1.server.max_mux; >@@ -4359,6 +4359,9 @@ static void smbXcli_negprot_smb2_done(struct tevent_req *subreq) > return; > } > >+ /* Hack. Ask for 128 initial credits. Add parameter ? */ >+ smb2cli_conn_set_max_credits(conn, 128); >+ > tevent_req_done(req); > } > >diff --git a/libcli/smb/smbXcli_base.h b/libcli/smb/smbXcli_base.h >index f7b60d3..4baee43 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, >@@ -429,7 +432,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 +444,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/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/include/includes.h b/source3/include/includes.h >index 1b22a57..cbb5dd9 100644 >--- a/source3/include/includes.h >+++ b/source3/include/includes.h >@@ -399,13 +399,13 @@ typedef char fstring[FSTRING_LEN]; > /* samba_setXXid functions. */ > #include "../lib/util/setid.h" > >+#include "lib/param/loadparm.h" >+ > /***** prototypes *****/ > #ifndef NO_PROTO_H > #include "proto.h" > #endif > >-#include "lib/param/loadparm.h" >- > /* String routines */ > > #include "srvstr.h" >diff --git a/source3/include/proto.h b/source3/include/proto.h >index 83ab77a..801ed0f 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); >@@ -1360,6 +1362,7 @@ int lp_name_cache_timeout(void); > int lp_client_signing(void); > int lp_server_signing(void); > int lp_client_ldap_sasl_wrapping(void); >+int lp_enum(const char *s,const struct enum_list *); > char *lp_parm_talloc_string(TALLOC_CTX *ctx, int snum, const char *type, const char *option, const char *def); > const char *lp_parm_const_string(int snum, const char *type, const char *option, const char *def); > struct loadparm_service; >@@ -1485,6 +1488,7 @@ char* lp_perfcount_module(TALLOC_CTX *ctx); > void widelinks_warning(int snum); > const char *lp_ncalrpc_dir(void); > void _lp_set_server_role(int server_role); >+void lp_set_cli_maxprotocol(int max_protocol); > > /* The following definitions come from param/loadparm_ctx.c */ > >diff --git a/source3/lib/util.c b/source3/lib/util.c >index 93aab3c..8138ae5 100644 >--- a/source3/lib/util.c >+++ b/source3/lib/util.c >@@ -565,22 +565,15 @@ char *get_mydnsdomname(TALLOC_CTX *ctx) > > 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); >+ extern const struct enum_list enum_protocol[]; >+ int ret = lp_enum(str, enum_protocol); >+ >+ if (ret == -1) { >+ DEBUG(0,("Unrecognised protocol level %s\n",str)); >+ ret = def; >+ } >+ >+ return ret; > } > > >diff --git a/source3/libsmb/cli_np_tstream.c b/source3/libsmb/cli_np_tstream.c >index c7ec664..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)) { >@@ -527,8 +528,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/libsmb/cliconnect.c b/source3/libsmb/cliconnect.c >index 7179c4f..9145cc3 100644 >--- a/source3/libsmb/cliconnect.c >+++ b/source3/libsmb/cliconnect.c >@@ -35,6 +35,7 @@ > #include "librpc/ndr/libndr.h" > #include "../libcli/smb/smbXcli_base.h" > #include "smb2cli.h" >+#include "smb2cli_fnum.h" > > #define STAR_SMBSERVER "*SMBSERVER" > >@@ -3122,8 +3123,9 @@ 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); >+ state->cli->timeout, >+ lp_cli_minprotocol(), >+ lp_cli_maxprotocol()); > if (tevent_req_nomem(subreq, req)) { > return; > } >diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c >index 4b4e1a0..e4b22ed 100644 >--- a/source3/libsmb/clifile.c >+++ b/source3/libsmb/clifile.c >@@ -21,6 +21,8 @@ > #include "includes.h" > #include "system/filesys.h" > #include "libsmb/libsmb.h" >+#include "libsmb/smb2cli.h" >+#include "libsmb/smb2cli_fnum.h" > #include "../lib/util/tevent_ntstatus.h" > #include "async_smb.h" > #include "libsmb/clirap.h" >@@ -1097,11 +1099,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 smb2cli_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 >@@ -1407,11 +1417,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 smb2cli_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 >@@ -1511,11 +1527,16 @@ 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 smb2cli_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 >@@ -1615,11 +1636,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 smb2cli_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 >@@ -1888,11 +1915,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 smb2cli_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 >@@ -2495,11 +2537,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 smb2cli_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 >@@ -3332,11 +3380,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 smb2cli_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 >@@ -3588,11 +3648,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 smb2cli_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 >@@ -3717,11 +3787,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 smb2cli_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 >@@ -3946,11 +4025,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 smb2cli_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 >diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c >index b0d3a4e..51e6f9f 100644 >--- a/source3/libsmb/clilist.c >+++ b/source3/libsmb/clilist.c >@@ -19,6 +19,8 @@ > > #include "includes.h" > #include "libsmb/libsmb.h" >+#include "libsmb/smb2cli.h" >+#include "libsmb/smb2cli_fnum.h" > #include "../lib/util/tevent_ntstatus.h" > #include "async_smb.h" > #include "trans2.h" >@@ -933,7 +935,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 +943,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 smb2cli_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 >diff --git a/source3/libsmb/clirap.c b/source3/libsmb/clirap.c >index 77e2fa3..f1255ef 100644 >--- a/source3/libsmb/clirap.c >+++ b/source3/libsmb/clirap.c >@@ -26,6 +26,8 @@ > #include "../lib/util/tevent_ntstatus.h" > #include "async_smb.h" > #include "libsmb/libsmb.h" >+#include "libsmb/smb2cli.h" >+#include "libsmb/smb2cli_fnum.h" > #include "libsmb/clirap.h" > #include "trans2.h" > #include "../libcli/smb/smbXcli_base.h" >@@ -845,11 +847,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 smb2cli_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 >@@ -879,11 +895,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; >@@ -956,11 +967,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 smb2cli_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 >@@ -986,7 +1007,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) >@@ -1130,6 +1151,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 smb2cli_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) { >@@ -1244,11 +1277,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 smb2cli_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 >@@ -1286,6 +1328,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 smb2cli_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); >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/clireadwrite.c b/source3/libsmb/clireadwrite.c >index 47e7f1b..352dfe0 100644 >--- a/source3/libsmb/clireadwrite.c >+++ b/source3/libsmb/clireadwrite.c >@@ -19,6 +19,8 @@ > > #include "includes.h" > #include "libsmb/libsmb.h" >+#include "libsmb/smb2cli.h" >+#include "libsmb/smb2cli_fnum.h" > #include "../lib/util/tevent_ntstatus.h" > #include "async_smb.h" > #include "trans2.h" >@@ -34,6 +36,13 @@ static size_t cli_read_max_bufsize(struct cli_state *cli) > uint32_t data_offset; > uint32_t useable_space = 0; > >+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { >+ return 0xFFFF; >+#if 0 >+ return smb2cli_conn_max_read_size(cli->conn); >+#endif >+ } >+ > data_offset = HDR_VWV; > data_offset += wct * sizeof(uint16_t); > data_offset += sizeof(uint16_t); /* byte count */ >@@ -533,10 +542,17 @@ struct tevent_req *cli_pull_send(TALLOC_CTX *mem_ctx, > size_left = size - state->requested; > request_thistime = MIN(size_left, state->chunk_size); > >- subreq->req = cli_readall_send( >- state->reqs, ev, cli, fnum, >- state->start_offset + state->requested, >- request_thistime); >+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) { >+ subreq->req = smb2cli_readall_fnum_send( >+ state->reqs, ev, cli, fnum, >+ state->start_offset + state->requested, >+ request_thistime); >+ } else { >+ subreq->req = cli_readall_send( >+ state->reqs, ev, cli, fnum, >+ state->start_offset + state->requested, >+ request_thistime); >+ } > > if (subreq->req == NULL) { > goto failed; >@@ -578,8 +594,14 @@ static void cli_pull_read_done(struct tevent_req *subreq) > return; > } > >- status = cli_readall_recv(subreq, &pull_subreq->received, >- &pull_subreq->buf); >+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { >+ status = smb2cli_readall_fnum_recv(subreq, &pull_subreq->received, >+ &pull_subreq->buf); >+ } else { >+ status = cli_readall_recv(subreq, &pull_subreq->received, >+ &pull_subreq->buf); >+ } >+ > if (!NT_STATUS_IS_OK(status)) { > tevent_req_nterror(state->req, status); > return; >@@ -636,11 +658,19 @@ static void cli_pull_read_done(struct tevent_req *subreq) > + 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 (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { >+ new_req = smb2cli_readall_fnum_send( >+ state->reqs, state->ev, state->cli, >+ state->fnum, >+ state->start_offset + state->requested, >+ request_thistime); >+ } else { >+ 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; >@@ -1078,7 +1108,11 @@ 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 = smb2cli_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; > } >@@ -1086,7 +1120,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 = smb2cli_writeall_recv(req, pwritten); >+ } else { >+ status = cli_writeall_recv(req, pwritten); >+ } > fail: > TALLOC_FREE(frame); > return status; >@@ -1156,12 +1194,23 @@ static bool cli_push_write_setup(struct tevent_req *req, > return true; > } > >- subreq = cli_writeall_send(substate, >+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { >+ subreq = smb2cli_writeall_send(substate, >+ state->ev, >+ state->cli, >+ state->fnum, >+ state->mode, >+ substate->buf, >+ substate->ofs, >+ substate->size); >+ } else { >+ 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; >@@ -1261,7 +1310,11 @@ static void cli_push_written(struct tevent_req *subreq) > state->reqs[idx] = NULL; > state->pending -= 1; > >- status = cli_writeall_recv(subreq, NULL); >+ if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) { >+ status = smb2cli_writeall_recv(subreq, NULL); >+ } else { >+ status = cli_writeall_recv(subreq, NULL); >+ } > TALLOC_FREE(subreq); > TALLOC_FREE(substate); > if (tevent_req_nterror(req, status)) { >diff --git a/source3/libsmb/clisecdesc.c b/source3/libsmb/clisecdesc.c >index 24da39d..e46928e 100644 >--- a/source3/libsmb/clisecdesc.c >+++ b/source3/libsmb/clisecdesc.c >@@ -19,7 +19,10 @@ > > #include "includes.h" > #include "libsmb/libsmb.h" >+#include "libsmb/smb2cli.h" >+#include "libsmb/smb2cli_fnum.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 +36,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 smb2cli_query_security_descriptor(cli, >+ fnum, >+ sec_info, >+ mem_ctx, >+ sd); >+ } >+ > SIVAL(param, 0, fnum); > SIVAL(param, 4, sec_info); > >@@ -95,6 +106,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 smb2cli_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", >diff --git a/source3/libsmb/smb2cli_fnum.c b/source3/libsmb/smb2cli_fnum.c >new file mode 100644 >index 0000000..fcd065c >--- /dev/null >+++ b/source3/libsmb/smb2cli_fnum.c >@@ -0,0 +1,1843 @@ >+/* >+ Unix SMB/CIFS implementation. >+ smb2 lib >+ 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 <http://www.gnu.org/licenses/>. >+*/ >+ >+/* >+ This code is a thin wrapper around the existing >+ smb2cli_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 "smb2cli_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" >+ >+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_PARAMETER; >+ } >+ 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 smb2cli_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_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 smb2cli_close_fnum(struct cli_state *cli, uint16_t fnum) >+{ >+ struct smb2_hnd *ph = NULL; >+ NTSTATUS status; >+ >+ 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 smb2cli_mkdir(struct cli_state *cli, const char *dname) >+{ >+ NTSTATUS status; >+ uint16_t fnum; >+ >+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { >+ return NT_STATUS_INVALID_PARAMETER; >+ } >+ >+ status = smb2cli_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 smb2cli_close_fnum(cli, fnum); >+} >+ >+/*************************************************************** >+ Small wrapper that allows SMB2 to delete a directory >+ Synchronous only. >+***************************************************************/ >+ >+NTSTATUS smb2cli_rmdir(struct cli_state *cli, const char *dname) >+{ >+ NTSTATUS status; >+ uint16_t fnum; >+ >+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { >+ return NT_STATUS_INVALID_PARAMETER; >+ } >+ >+ status = smb2cli_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 smb2cli_close_fnum(cli, fnum); >+} >+ >+/*************************************************************** >+ Small wrapper that allows SMB2 to unlink a pathname. >+ Synchronous only. >+***************************************************************/ >+ >+NTSTATUS smb2cli_unlink(struct cli_state *cli, const char *fname) >+{ >+ NTSTATUS status; >+ uint16_t fnum; >+ >+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { >+ return NT_STATUS_INVALID_PARAMETER; >+ } >+ >+ status = smb2cli_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 smb2cli_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 smb2cli_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_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 = smb2cli_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) { >+ smb2cli_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 smb2cli_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_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 = smb2cli_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 = smb2cli_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; >+ } >+ >+ smb2cli_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, >+ TALLOC_CTX *ctx, >+ const char *name, >+ uint32_t desired_access, >+ uint16_t *pfnum) >+{ >+ NTSTATUS status; >+ size_t namelen = strlen(name); >+ >+ /* SMB2 is pickier about pathnames. Ensure it doesn't >+ end in a '\' */ >+ if (namelen > 0 && name[namelen-1] == '\\') { >+ char *modname = talloc_strdup(ctx, name); >+ modname[namelen-1] = '\0'; >+ name = modname; >+ } >+ >+ /* Try to open a file handle first. */ >+ status = smb2cli_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 = smb2cli_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); >+ } >+ >+ return status; >+} >+ >+/*************************************************************** >+ Wrapper that allows SMB2 to query a path info (ALTNAME level). >+ Synchronous only. >+***************************************************************/ >+ >+NTSTATUS smb2cli_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_protocol(cli->conn) < PROTOCOL_SMB2_02) { >+ status = NT_STATUS_INVALID_PARAMETER; >+ goto fail; >+ } >+ >+ status = get_fnum_from_path(cli, >+ frame, >+ 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) { >+ smb2cli_close_fnum(cli, fnum); >+ } >+ TALLOC_FREE(frame); >+ return status; >+} >+ >+ >+/*************************************************************** >+ Wrapper that allows SMB2 to query a fnum info (basic level). >+ Synchronous only. >+***************************************************************/ >+ >+NTSTATUS smb2cli_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_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 smb2cli_qfileinfo_basic(). >+ Synchronous only. >+***************************************************************/ >+ >+NTSTATUS smb2cli_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 = smb2cli_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 query a pathname info (basic level). >+ Implement on top of smb2cli_qfileinfo_basic(). >+ Synchronous only. >+***************************************************************/ >+ >+NTSTATUS smb2cli_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_protocol(cli->conn) < PROTOCOL_SMB2_02) { >+ status = NT_STATUS_INVALID_PARAMETER; >+ goto fail; >+ } >+ >+ status = get_fnum_from_path(cli, >+ frame, >+ 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 = smb2cli_qfileinfo_basic(cli, >+ fnum, >+ mode, >+ size, >+ create_time, >+ access_time, >+ write_time, >+ change_time, >+ ino); >+ >+ fail: >+ >+ if (fnum != -1) { >+ smb2cli_close_fnum(cli, fnum); >+ } >+ >+ TALLOC_FREE(frame); >+ return status; >+} >+ >+/*************************************************************** >+ Wrapper that allows SMB2 to query pathname streams. >+ Synchronous only. >+***************************************************************/ >+ >+NTSTATUS smb2cli_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_protocol(cli->conn) < PROTOCOL_SMB2_02) { >+ status = NT_STATUS_INVALID_PARAMETER; >+ goto fail; >+ } >+ >+ status = get_fnum_from_path(cli, >+ frame, >+ 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) { >+ smb2cli_close_fnum(cli, fnum); >+ } >+ >+ TALLOC_FREE(frame); >+ return status; >+} >+ >+/*************************************************************** >+ Wrapper that allows SMB2 to set pathname attributes. >+ Synchronous only. >+***************************************************************/ >+ >+NTSTATUS smb2cli_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[36]; >+ DATA_BLOB inbuf = data_blob_null; >+ TALLOC_CTX *frame = talloc_stackframe(); >+ >+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) { >+ status = NT_STATUS_INVALID_PARAMETER; >+ goto fail; >+ } >+ >+ status = get_fnum_from_path(cli, >+ frame, >+ 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); >+ } >+ >+ 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) { >+ smb2cli_close_fnum(cli, fnum); >+ } >+ >+ TALLOC_FREE(frame); >+ return status; >+} >+ >+/*************************************************************** >+ Wrapper that allows SMB2 to set file handle times. >+ Synchronous only. >+***************************************************************/ >+ >+NTSTATUS smb2cli_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[36]; >+ DATA_BLOB inbuf = data_blob_null; >+ >+ 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); >+ >+ 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 smb2cli_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_protocol(cli->conn) < PROTOCOL_SMB2_02) { >+ status = NT_STATUS_INVALID_PARAMETER; >+ goto fail; >+ } >+ >+ /* First open the top level directory. */ >+ status = smb2cli_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) { >+ smb2cli_close_fnum(cli, fnum); >+ } >+ >+ TALLOC_FREE(frame); >+ return status; >+} >+ >+/*************************************************************** >+ Wrapper that allows SMB2 to query a security descriptor. >+ Synchronous only. >+***************************************************************/ >+ >+NTSTATUS smb2cli_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; >+ >+ 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; >+ } >+ >+ /* 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, >+ mem_ctx, >+ &outbuf); >+ >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; >+ } >+ >+ /* Parse the reply. */ >+ status = unmarshall_sec_desc(mem_ctx, >+ outbuf.data, >+ outbuf.length, >+ &lsd); >+ >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; >+ } >+ >+ if (ppsd != NULL) { >+ *ppsd = lsd; >+ } else { >+ TALLOC_FREE(lsd); >+ } >+ >+ return status; >+} >+ >+/*************************************************************** >+ Wrapper that allows SMB2 to set a security descriptor. >+ Synchronous only. >+***************************************************************/ >+ >+NTSTATUS smb2cli_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_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 smb2cli_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_protocol(cli->conn) < PROTOCOL_SMB2_02) { >+ status = NT_STATUS_INVALID_PARAMETER; >+ goto fail; >+ } >+ >+ status = get_fnum_from_path(cli, >+ frame, >+ 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) { >+ smb2cli_close_fnum(cli, fnum); >+ } >+ >+ TALLOC_FREE(frame); >+ return status; >+} >+ >+/*************************************************************** >+ Wrapper that allows SMB2 async read 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_pull() >+ for free :-). >+***************************************************************/ >+ >+struct smb2cli_readall_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 smb2cli_readall_fnum_done(struct tevent_req *subreq); >+ >+struct tevent_req *smb2cli_readall_fnum_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 smb2cli_readall_state *state; >+ >+ req = tevent_req_create(mem_ctx, &state, struct smb2cli_readall_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 (!NT_STATUS_IS_OK(status)) { >+ return NULL; >+ } >+ >+ 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, smb2cli_readall_fnum_done, req); >+ return req; >+} >+ >+static void smb2cli_readall_fnum_done(struct tevent_req *subreq) >+{ >+ struct tevent_req *req = tevent_req_callback_data( >+ subreq, struct tevent_req); >+ struct smb2cli_readall_state *state = tevent_req_data( >+ req, struct smb2cli_readall_state); >+ uint32_t received = 0; >+ uint8_t *buf = NULL; >+ NTSTATUS status; >+ >+ status = smb2cli_read_recv(subreq, state, &buf, &received); >+ if (tevent_req_nterror(req, status)) { >+ return; >+ } >+ >+ if (received == 0) { >+ /* EOF */ >+ tevent_req_done(req); >+ return; >+ } >+ >+ if (received > state->size) { >+ tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE); >+ 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. smb2cli_read 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 = smb2cli_read_send(state, >+ state->ev, >+ state->cli->conn, >+ state->cli->timeout, >+ state->cli->smb2.session, >+ state->cli->smb2.tcon, >+ state->size - state->received, >+ state->start_offset + state->received, >+ state->ph->fid_persistent, >+ state->ph->fid_volatile, >+ 0, /* minimum_count */ >+ 0); /* remaining_bytes */ >+ >+ if (tevent_req_nomem(subreq, req)) { >+ return; >+ } >+ tevent_req_set_callback(subreq, smb2cli_readall_fnum_done, req); >+} >+ >+NTSTATUS smb2cli_readall_fnum_recv(struct tevent_req *req, >+ ssize_t *received, >+ uint8_t **rcvbuf) >+{ >+ NTSTATUS status; >+ struct smb2cli_readall_state *state = tevent_req_data( >+ req, struct smb2cli_readall_state); >+ >+ if (tevent_req_is_nterror(req, &status)) { >+ return status; >+ } >+ *received = (ssize_t)state->received; >+ *rcvbuf = state->buf; >+ 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 smb2cli_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 smb2cli_writeall_written(struct tevent_req *req); >+ >+struct tevent_req *smb2cli_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 smb2cli_writeall_state *state = NULL; >+ >+ req = tevent_req_create(mem_ctx, &state, struct smb2cli_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 (!NT_STATUS_IS_OK(status)) { >+ return NULL; >+ } >+ >+ 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, smb2cli_writeall_written, req); >+ return req; >+} >+ >+static void smb2cli_writeall_written(struct tevent_req *subreq) >+{ >+ struct tevent_req *req = tevent_req_callback_data( >+ subreq, struct tevent_req); >+ struct smb2cli_writeall_state *state = tevent_req_data( >+ req, struct smb2cli_writeall_state); >+ NTSTATUS status; >+ uint32_t written, to_write; >+ >+ 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; >+ } >+ >+ 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, smb2cli_writeall_written, req); >+} >+ >+NTSTATUS smb2cli_writeall_recv(struct tevent_req *req, >+ size_t *pwritten) >+{ >+ struct smb2cli_writeall_state *state = tevent_req_data( >+ req, struct smb2cli_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/smb2cli_fnum.h b/source3/libsmb/smb2cli_fnum.h >new file mode 100644 >index 0000000..49c1555 >--- /dev/null >+++ b/source3/libsmb/smb2cli_fnum.h >@@ -0,0 +1,131 @@ >+/* >+ 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 <http://www.gnu.org/licenses/>. >+*/ >+ >+#ifndef __SMB2CLI_FNUM_H__ >+#define __SMB2CLI_FNUM_H__ >+ >+struct smbXcli_conn; >+struct smbXcli_session; >+struct cli_state; >+struct file_info; >+ >+NTSTATUS smb2cli_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 smb2cli_close_fnum(struct cli_state *cli, uint16_t fnum); >+NTSTATUS smb2cli_mkdir(struct cli_state *cli, const char *dirname); >+NTSTATUS smb2cli_rmdir(struct cli_state *cli, const char *dirname); >+NTSTATUS smb2cli_unlink(struct cli_state *cli,const char *fname); >+NTSTATUS smb2cli_list(struct cli_state *cli, >+ const char *pathname, >+ NTSTATUS (*fn)(const char *, >+ struct file_info *, >+ const char *, >+ void *), >+ void *state); >+NTSTATUS smb2cli_qpathinfo_basic(struct cli_state *cli, >+ const char *name, >+ SMB_STRUCT_STAT *sbuf, >+ uint32_t *attributes); >+NTSTATUS smb2cli_qpathinfo_alt_name(struct cli_state *cli, >+ const char *name, >+ fstring alt_name); >+NTSTATUS smb2cli_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 smb2cli_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 smb2cli_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 smb2cli_qpathinfo_streams(struct cli_state *cli, >+ const char *name, >+ TALLOC_CTX *mem_ctx, >+ unsigned int *pnum_streams, >+ struct stream_struct **pstreams); >+NTSTATUS smb2cli_setatr(struct cli_state *cli, >+ const char *fname, >+ uint16_t attr, >+ time_t mtime); >+NTSTATUS smb2cli_setattrE(struct cli_state *cli, >+ uint16_t fnum, >+ time_t change_time, >+ time_t access_time, >+ time_t write_time); >+NTSTATUS smb2cli_dskattr(struct cli_state *cli, >+ int *bsize, >+ int *total, >+ int *avail); >+NTSTATUS smb2cli_query_security_descriptor(struct cli_state *cli, >+ uint16_t fnum, >+ uint32_t sec_info, >+ TALLOC_CTX *mem_ctx, >+ struct security_descriptor **ppsd); >+NTSTATUS smb2cli_set_security_descriptor(struct cli_state *cli, >+ uint16_t fnum, >+ uint32_t sec_info, >+ const struct security_descriptor *sd); >+NTSTATUS smb2cli_rename(struct cli_state *cli, >+ const char *fname_src, >+ const char *fname_dst); >+struct tevent_req *smb2cli_readall_fnum_send(TALLOC_CTX *mem_ctx, >+ struct tevent_context *ev, >+ struct cli_state *cli, >+ uint16_t fnum, >+ off_t offset, >+ size_t size); >+NTSTATUS smb2cli_readall_fnum_recv(struct tevent_req *req, >+ ssize_t *received, >+ uint8_t **rcvbuf); >+struct tevent_req *smb2cli_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 smb2cli_writeall_recv(struct tevent_req *req, >+ size_t *pwritten); >+#endif /* __SMB2CLI_FNUM_H__ */ >diff --git a/source3/libsmb/smb2cli_tcon.c b/source3/libsmb/smb2cli_tcon.c >index ab97f8d..bf74c1b 100644 >--- a/source3/libsmb/smb2cli_tcon.c >+++ b/source3/libsmb/smb2cli_tcon.c >@@ -22,6 +22,7 @@ > #include "async_smb.h" > #include "../libcli/smb/smbXcli_base.h" > #include "smb2cli.h" >+#include "smb2cli_fnum.h" > #include "libsmb/proto.h" > #include "lib/util/tevent_ntstatus.h" > >diff --git a/source3/param/loadparm.c b/source3/param/loadparm.c >index fa2f9b6..078bea6 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; >@@ -1328,7 +1330,7 @@ static bool lp_bool(const char *s) > /******************************************************************* > convenience routine to return enum parameters. > ********************************************************************/ >-static int lp_enum(const char *s,const struct enum_list *_enum) >+int lp_enum(const char *s,const struct enum_list *_enum) > { > int i; > >@@ -5538,3 +5540,8 @@ int lp_security(void) > return lp_find_security(lp__server_role(), > lp__security()); > } >+ >+void lp_set_cli_maxprotocol(int max_protocol) >+{ >+ Globals.cli_maxprotocol = max_protocol; >+} >diff --git a/source3/torture/test_smb2.c b/source3/torture/test_smb2.c >index ec695da..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; >@@ -91,7 +92,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; >@@ -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; >@@ -349,7 +352,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 +548,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)) > { >@@ -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)); >@@ -605,7 +609,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)) > { >@@ -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; >@@ -670,7 +676,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; >@@ -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; >@@ -765,7 +772,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; >@@ -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; >@@ -1172,7 +1180,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; >@@ -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; >diff --git a/source3/utils/smbcacls.c b/source3/utils/smbcacls.c >index 39400c8..4581843 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_cli_maxprotocol(interpret_protocol(poptGetOptArg(pc), PROTOCOL_NT1)); >+ break; > } > } > >diff --git a/source3/wscript_build b/source3/wscript_build >index 19c6d08..4b32545 100755 >--- a/source3/wscript_build >+++ b/source3/wscript_build >@@ -134,6 +134,7 @@ LIBSMB_SRC = '''libsmb/clientgen.c libsmb/cliconnect.c libsmb/clifile.c > libsmb/cli_np_tstream.c > libsmb/reparse_symlink.c > libsmb/clisymlink.c >+ libsmb/smb2cli_fnum.c > libsmb/smbsock_connect.c''' > > LIBMSRPC_SRC = ''' >-- >1.8.3 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Actions:
View
Attachments on
bug 9974
:
9014
|
9123
|
9135
|
9136
|
9139
|
9148
|
9159