From 030a6e7805241c172b4b7c70ad5e1248960e334b Mon Sep 17 00:00:00 2001 From: Jeremy Allison 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 --- 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 . */ -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 . +*/ + +/* + 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 . +*/ + +#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