[PATCH] smbd: Fix snapshot query on shares with DFS enabled
Jeremy Allison
jra at samba.org
Sat Aug 20 03:37:16 UTC 2016
On Fri, Aug 19, 2016 at 11:22:54AM +0300, Uri Simchoni wrote:
> On 08/19/2016 12:51 AM, Jeremy Allison wrote:
> >
> > Once this is in I'll do the same fix for accessing shadow
> > copies over SMB2.
> >
> > Cheers,
> >
> > Jeremy.
> >
>
> Pushed with a small space-before-tab correction in "libsmb: Add uint16_t
> addtional_flags2 to cli_trans_send()"
Thanks for the fix.
Here is the follow-up patchset to fix getting shadow
copies using the 'allinfo' command over SMB2+.
Passes local make test.
Patch #1 is a leftover I forgot from the previous
patchset.
Patch #2 took FAR TOO LONG to figure out. 6 hours
of staring at smbclient SMB2create calls returning
NT_STATUS_INVALID_PARAMETER until I finally started
looking at padding :-).
Please review and push !
Cheers,
Jeremy.
-------------- next part --------------
>From 4262bde33510b7b7210bc706ccbded51a6ec64a7 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Fri, 19 Aug 2016 16:57:27 -0700
Subject: [PATCH 1/6] s3: smbclient. Ensure we don't crash by freeing
uninitialized *snapshots.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12165
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/client/client.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/source3/client/client.c b/source3/client/client.c
index 7fbfdf0..e7531d3 100644
--- a/source3/client/client.c
+++ b/source3/client/client.c
@@ -1696,7 +1696,7 @@ static int do_allinfo(const char *name)
unsigned int num_streams;
struct stream_struct *streams;
int num_snapshots;
- char **snapshots;
+ char **snapshots = NULL;
unsigned int i;
NTSTATUS status;
--
2.8.0.rc3.226.g39d4020
>From d7ebd3be018a20b572c46397578b4c9219c83839 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Fri, 19 Aug 2016 16:58:39 -0700
Subject: [PATCH 2/6] s3: libsmb: Correctly align create contexts in a create
call.
SMB2 shadow copy requests are the first time we've used
create contexts in anger in this codepath. This took me
longer than I'd like to admit to find :-).
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166
Signed-off-by: Jeremy Allison <jra at samba.org>
---
libcli/smb/smb2cli_create.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/libcli/smb/smb2cli_create.c b/libcli/smb/smb2cli_create.c
index 0db546c..778b501 100644
--- a/libcli/smb/smb2cli_create.c
+++ b/libcli/smb/smb2cli_create.c
@@ -113,6 +113,7 @@ struct tevent_req *smb2cli_create_send(
blobs_offset = ((blobs_offset + 3) & ~3);
if (blob.length > 0) {
+ blobs_offset = ((blobs_offset + 7) & ~7);
SIVAL(fixed, 48, blobs_offset + SMB2_HDR_BODY + 56);
SIVAL(fixed, 52, blob.length);
}
--
2.8.0.rc3.226.g39d4020
>From 409ea0bcbf501588e63d0ece5ce1ea0b68f15db5 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Thu, 18 Aug 2016 17:15:01 -0700
Subject: [PATCH 3/6] s3: libsmb: Add return args to
clistr_is_previous_version_path().
Not yet used - we will use these to construct the SMB2 TWrp blob.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/libsmb/clifile.c | 28 ++++++++++++++--------------
source3/libsmb/clilist.c | 4 ++--
source3/libsmb/clistr.c | 17 ++++++++++++++++-
source3/libsmb/proto.h | 5 ++++-
4 files changed, 36 insertions(+), 18 deletions(-)
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index 0964b3a..75ec3a2 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -197,7 +197,7 @@ struct tevent_req *cli_setpathinfo_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(path) &&
+ if (clistr_is_previous_version_path(path, NULL, NULL, NULL) &&
!INFO_LEVEL_IS_UNIX(level)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -1155,7 +1155,7 @@ struct tevent_req *cli_rename_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(fname_src)) {
+ if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -1290,7 +1290,7 @@ static struct tevent_req *cli_ntrename_internal_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(fname_src)) {
+ if (clistr_is_previous_version_path(fname_src, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -1495,7 +1495,7 @@ struct tevent_req *cli_unlink_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(fname)) {
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -1610,7 +1610,7 @@ struct tevent_req *cli_mkdir_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(dname)) {
+ if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -1725,7 +1725,7 @@ struct tevent_req *cli_rmdir_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(dname)) {
+ if (clistr_is_previous_version_path(dname, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -1978,7 +1978,7 @@ static struct tevent_req *cli_ntcreate1_send(TALLOC_CTX *mem_ctx,
fname, strlen(fname)+1,
&converted_len);
- if (clistr_is_previous_version_path(fname)) {
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -2282,7 +2282,7 @@ struct tevent_req *cli_nttrans_create_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(fname)) {
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -2508,7 +2508,7 @@ struct tevent_req *cli_openx_create(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(fname)) {
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -3765,7 +3765,7 @@ struct tevent_req *cli_getatr_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(fname)) {
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -4057,7 +4057,7 @@ struct tevent_req *cli_setatr_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(fname)) {
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -4178,7 +4178,7 @@ struct tevent_req *cli_chkpath_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(fname)) {
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -4489,7 +4489,7 @@ struct tevent_req *cli_ctemp_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(path)) {
+ if (clistr_is_previous_version_path(path, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -5651,7 +5651,7 @@ struct tevent_req *cli_qpathinfo_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(fname) &&
+ if (clistr_is_previous_version_path(fname, NULL, NULL, NULL) &&
!INFO_LEVEL_IS_UNIX(level)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
diff --git a/source3/libsmb/clilist.c b/source3/libsmb/clilist.c
index d6116f0..41f5851 100644
--- a/source3/libsmb/clilist.c
+++ b/source3/libsmb/clilist.c
@@ -600,7 +600,7 @@ static struct tevent_req *cli_list_trans_send(TALLOC_CTX *mem_ctx,
return tevent_req_post(req, ev);
}
- if (clistr_is_previous_version_path(state->mask)) {
+ if (clistr_is_previous_version_path(state->mask, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
@@ -792,7 +792,7 @@ static void cli_list_trans_done(struct tevent_req *subreq)
}
param_len = talloc_get_size(state->param);
- if (clistr_is_previous_version_path(state->mask)) {
+ if (clistr_is_previous_version_path(state->mask, NULL, NULL, NULL)) {
additional_flags2 = FLAGS2_REPARSE_PATH;
}
diff --git a/source3/libsmb/clistr.c b/source3/libsmb/clistr.c
index c3611be..154b9a1 100644
--- a/source3/libsmb/clistr.c
+++ b/source3/libsmb/clistr.c
@@ -38,7 +38,10 @@ size_t clistr_pull_talloc(TALLOC_CTX *ctx,
flags);
}
-bool clistr_is_previous_version_path(const char *path)
+bool clistr_is_previous_version_path(const char *path,
+ const char **startp,
+ const char **endp,
+ time_t *ptime)
{
char *q;
time_t timestamp;
@@ -63,5 +66,17 @@ bool clistr_is_previous_version_path(const char *path)
if (q[0] != '\0' && q[0] != '\\') {
return false;
}
+ if (startp) {
+ *startp = p;
+ }
+ if (endp) {
+ if (q[0] == '\\') {
+ q++;
+ }
+ *endp = q;
+ }
+ if (ptime) {
+ *ptime = timestamp;
+ }
return true;
}
diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
index f9bb985..c0e1b74 100644
--- a/source3/libsmb/proto.h
+++ b/source3/libsmb/proto.h
@@ -868,7 +868,10 @@ size_t clistr_pull_talloc(TALLOC_CTX *ctx,
const void *src,
int src_len,
int flags);
-bool clistr_is_previous_version_path(const char *path);
+bool clistr_is_previous_version_path(const char *path,
+ const char **startp,
+ const char **endp,
+ time_t *ptime);
/* The following definitions come from libsmb/clitrans.c */
--
2.8.0.rc3.226.g39d4020
>From 072bece6388ab317d3cec23f81ae9fc620eed28a Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 16 Aug 2016 15:26:53 -0700
Subject: [PATCH 4/6] s3: libsmb: Add cli_smb2_shadow_copy_data() function that
gets shadow copy info over SMB2.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/libsmb/cli_smb2_fnum.c | 223 +++++++++++++++++++++++++++++++++++++++++
source3/libsmb/cli_smb2_fnum.h | 6 ++
2 files changed, 229 insertions(+)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index c5b1434..6837489 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -39,6 +39,7 @@
#include "../libcli/security/security.h"
#include "lib/util_ea.h"
#include "librpc/gen_ndr/ndr_ioctl.h"
+#include "ntioctl.h"
struct smb2_hnd {
uint64_t fid_persistent;
@@ -2873,3 +2874,225 @@ NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written)
tevent_req_received(req);
return NT_STATUS_OK;
}
+
+/***************************************************************
+ SMB2 enum shadow copy data.
+***************************************************************/
+
+struct cli_smb2_shadow_copy_data_fnum_state {
+ struct cli_state *cli;
+ uint16_t fnum;
+ struct smb2_hnd *ph;
+ DATA_BLOB out_input_buffer;
+ DATA_BLOB out_output_buffer;
+};
+
+static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq);
+
+static struct tevent_req *cli_smb2_shadow_copy_data_fnum_send(
+ TALLOC_CTX *mem_ctx,
+ struct tevent_context *ev,
+ struct cli_state *cli,
+ uint16_t fnum,
+ bool get_names)
+{
+ struct tevent_req *req, *subreq;
+ struct cli_smb2_close_fnum_state *state;
+ NTSTATUS status;
+
+ req = tevent_req_create(mem_ctx, &state,
+ struct cli_smb2_shadow_copy_data_fnum_state);
+ if (req == NULL) {
+ return NULL;
+ }
+
+ if (smbXcli_conn_protocol(cli->conn) < PROTOCOL_SMB2_02) {
+ tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
+ return tevent_req_post(req, ev);
+ }
+
+ state->cli = cli;
+ state->fnum = fnum;
+
+ status = map_fnum_to_smb2_handle(cli, fnum, &state->ph);
+ if (tevent_req_nterror(req, status)) {
+ return tevent_req_post(req, ev);
+ }
+
+ /*
+ * TODO. Under SMB2 we should send a zero max_output_length
+ * ioctl to get the required size, then send another ioctl
+ * to get the data, but the current SMB1 implementation just
+ * does one roundtrip with a 64K buffer size. Do the same
+ * for now. JRA.
+ */
+
+ subreq = smb2cli_ioctl_send(state, ev, state->cli->conn,
+ state->cli->timeout,
+ state->cli->smb2.session,
+ state->cli->smb2.tcon,
+ state->ph->fid_persistent, /* in_fid_persistent */
+ state->ph->fid_volatile, /* in_fid_volatile */
+ FSCTL_GET_SHADOW_COPY_DATA,
+ 0, /* in_max_input_length */
+ NULL, /* in_input_buffer */
+ get_names ?
+ CLI_BUFFER_SIZE : 16, /* in_max_output_length */
+ NULL, /* in_output_buffer */
+ SMB2_IOCTL_FLAG_IS_FSCTL);
+
+ if (tevent_req_nomem(subreq, req)) {
+ return tevent_req_post(req, ev);
+ }
+ tevent_req_set_callback(subreq,
+ cli_smb2_shadow_copy_data_fnum_done,
+ req);
+
+ return req;
+}
+
+static void cli_smb2_shadow_copy_data_fnum_done(struct tevent_req *subreq)
+{
+ struct tevent_req *req = tevent_req_callback_data(
+ subreq, struct tevent_req);
+ struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
+ req, struct cli_smb2_shadow_copy_data_fnum_state);
+ NTSTATUS status;
+
+ status = smb2cli_ioctl_recv(subreq, state,
+ &state->out_input_buffer,
+ &state->out_output_buffer);
+ TALLOC_FREE(subreq);
+ if (tevent_req_nterror(req, status)) {
+ return;
+ }
+ tevent_req_done(req);
+}
+
+static NTSTATUS cli_smb2_shadow_copy_data_fnum_recv(struct tevent_req *req,
+ TALLOC_CTX *mem_ctx,
+ bool get_names,
+ char ***pnames,
+ int *pnum_names)
+{
+ struct cli_smb2_shadow_copy_data_fnum_state *state = tevent_req_data(
+ req, struct cli_smb2_shadow_copy_data_fnum_state);
+ char **names = NULL;
+ uint32_t num_names = 0;
+ uint32_t num_names_returned = 0;
+ uint32_t dlength = 0;
+ uint32_t i;
+ uint8_t *endp = NULL;
+ NTSTATUS status;
+
+ if (tevent_req_is_nterror(req, &status)) {
+ return status;
+ }
+
+ if (state->out_output_buffer.length < 16) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ num_names = IVAL(state->out_output_buffer.data, 0);
+ num_names_returned = IVAL(state->out_output_buffer.data, 4);
+ dlength = IVAL(state->out_output_buffer.data, 8);
+
+ if (num_names > 0x7FFFFFFF) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ if (get_names == false) {
+ *pnum_names = (int)num_names;
+ return NT_STATUS_OK;
+ }
+ if (num_names != num_names_returned) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (dlength + 12 < 12) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (dlength + 12 > state->out_output_buffer.length) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ if (state->out_output_buffer.length +
+ (2 * sizeof(SHADOW_COPY_LABEL)) <
+ state->out_output_buffer.length) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+
+ names = talloc_array(mem_ctx, char *, num_names_returned);
+ if (names == NULL) {
+ return NT_STATUS_NO_MEMORY;
+ }
+
+ endp = state->out_output_buffer.data +
+ state->out_output_buffer.length;
+
+ for (i=0; i<num_names_returned; i++) {
+ bool ret;
+ uint8_t *src;
+ size_t converted_size;
+
+ src = state->out_output_buffer.data + 12 +
+ (i * 2 * sizeof(SHADOW_COPY_LABEL));
+
+ if (src + (2 * sizeof(SHADOW_COPY_LABEL)) > endp) {
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ ret = convert_string_talloc(
+ names, CH_UTF16LE, CH_UNIX,
+ src, 2 * sizeof(SHADOW_COPY_LABEL),
+ &names[i], &converted_size);
+ if (!ret) {
+ TALLOC_FREE(names);
+ return NT_STATUS_INVALID_NETWORK_RESPONSE;
+ }
+ }
+ *pnum_names = num_names;
+ *pnames = names;
+ return NT_STATUS_OK;
+}
+
+NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ uint16_t fnum,
+ bool get_names,
+ char ***pnames,
+ int *pnum_names)
+{
+ TALLOC_CTX *frame = talloc_stackframe();
+ struct tevent_context *ev;
+ struct tevent_req *req;
+ NTSTATUS status = NT_STATUS_NO_MEMORY;
+
+ if (smbXcli_conn_has_async_calls(cli->conn)) {
+ /*
+ * Can't use sync call while an async call is in flight
+ */
+ status = NT_STATUS_INVALID_PARAMETER;
+ goto fail;
+ }
+ ev = samba_tevent_context_init(frame);
+ if (ev == NULL) {
+ goto fail;
+ }
+ req = cli_smb2_shadow_copy_data_fnum_send(frame,
+ ev,
+ cli,
+ fnum,
+ get_names);
+ if (req == NULL) {
+ goto fail;
+ }
+ if (!tevent_req_poll_ntstatus(req, ev, &status)) {
+ goto fail;
+ }
+ status = cli_smb2_shadow_copy_data_fnum_recv(req,
+ mem_ctx,
+ get_names,
+ pnames,
+ pnum_names);
+ fail:
+ TALLOC_FREE(frame);
+ return status;
+}
diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
index ceb5629..0436c68 100644
--- a/source3/libsmb/cli_smb2_fnum.h
+++ b/source3/libsmb/cli_smb2_fnum.h
@@ -184,4 +184,10 @@ struct tevent_req *cli_smb2_splice_send(TALLOC_CTX *mem_ctx,
off_t size, off_t src_offset, off_t dst_offset,
int (*splice_cb)(off_t n, void *priv), void *priv);
NTSTATUS cli_smb2_splice_recv(struct tevent_req *req, off_t *written);
+NTSTATUS cli_smb2_shadow_copy_data(TALLOC_CTX *mem_ctx,
+ struct cli_state *cli,
+ uint16_t fnum,
+ bool get_names,
+ char ***pnames,
+ int *pnum_names);
#endif /* __SMB2CLI_FNUM_H__ */
--
2.8.0.rc3.226.g39d4020
>From a1628800e425388eb0e68e71d643e5ab3b720569 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Tue, 16 Aug 2016 15:27:55 -0700
Subject: [PATCH 5/6] s3: libsmb: Plumb new SMB2 shadow copy call into
cli_shadow_copy_data().
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/libsmb/clifile.c | 13 ++++++++++++-
1 file changed, 12 insertions(+), 1 deletion(-)
diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
index 75ec3a2..fca7c91 100644
--- a/source3/libsmb/clifile.c
+++ b/source3/libsmb/clifile.c
@@ -6116,11 +6116,22 @@ NTSTATUS cli_shadow_copy_data(TALLOC_CTX *mem_ctx, struct cli_state *cli,
uint16_t fnum, bool get_names,
char ***pnames, int *pnum_names)
{
- TALLOC_CTX *frame = talloc_stackframe();
+ TALLOC_CTX *frame = NULL;
struct tevent_context *ev;
struct tevent_req *req;
NTSTATUS status = NT_STATUS_NO_MEMORY;
+ if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
+ return cli_smb2_shadow_copy_data(mem_ctx,
+ cli,
+ fnum,
+ get_names,
+ pnames,
+ pnum_names);
+ }
+
+ frame = talloc_stackframe();
+
if (smbXcli_conn_has_async_calls(cli->conn)) {
/*
* Can't use sync call while an async call is in flight
--
2.8.0.rc3.226.g39d4020
>From 68946e5373b1eb77a7d725528c5b54251e3578a9 Mon Sep 17 00:00:00 2001
From: Jeremy Allison <jra at samba.org>
Date: Fri, 19 Aug 2016 17:00:25 -0700
Subject: [PATCH 6/6] s3: libsmb: Add the capability to find a @GMT- path in an
SMB2 create and transform to a timewarp token.
BUG: https://bugzilla.samba.org/show_bug.cgi?id=12166
Signed-off-by: Jeremy Allison <jra at samba.org>
---
source3/libsmb/cli_smb2_fnum.c | 45 ++++++++++++++++++++++++++++++++++++++++--
1 file changed, 43 insertions(+), 2 deletions(-)
diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
index 6837489..a70bb65 100644
--- a/source3/libsmb/cli_smb2_fnum.c
+++ b/source3/libsmb/cli_smb2_fnum.c
@@ -178,6 +178,10 @@ struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
struct tevent_req *req, *subreq;
struct cli_smb2_create_fnum_state *state;
size_t fname_len = 0;
+ const char *startp = NULL;
+ const char *endp = NULL;
+ time_t tstamp = (time_t)0;
+ struct smb2_create_blobs *cblobs = NULL;
req = tevent_req_create(mem_ctx, &state,
struct cli_smb2_create_fnum_state);
@@ -195,14 +199,51 @@ struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
create_options |= FILE_OPEN_FOR_BACKUP_INTENT;
}
+ /* Check for @GMT- paths. Remove the @GMT and turn into TWrp if so. */
+ fname_len = strlen(fname);
+ if (clistr_is_previous_version_path(fname, &startp, &endp, &tstamp)) {
+ size_t len_before_gmt = startp - fname;
+ size_t len_after_gmt = fname + fname_len - endp;
+ DATA_BLOB twrp_blob;
+ NTTIME ntt;
+ NTSTATUS status;
+
+ char *new_fname = talloc_array(state, char,
+ len_before_gmt + len_after_gmt + 1);
+
+ if (tevent_req_nomem(new_fname, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ memcpy(new_fname, fname, len_before_gmt);
+ memcpy(new_fname + len_before_gmt, endp, len_after_gmt + 1);
+ fname = new_fname;
+ fname_len = len_before_gmt + len_after_gmt;
+
+ unix_to_nt_time(&ntt, tstamp);
+ twrp_blob = data_blob_const((const void *)&ntt, 8);
+
+ cblobs = talloc_zero(state, struct smb2_create_blobs);
+ if (tevent_req_nomem(cblobs, req)) {
+ return tevent_req_post(req, ev);
+ }
+
+ status = smb2_create_blob_add(state, cblobs,
+ SMB2_CREATE_TAG_TWRP, twrp_blob);
+ if (!NT_STATUS_IS_OK(status)) {
+ tevent_req_nterror(req, status);
+ return tevent_req_post(req, ev);
+ }
+ }
+
/* SMB2 is pickier about pathnames. Ensure it doesn't
start in a '\' */
if (*fname == '\\') {
fname++;
+ fname_len--;
}
/* Or end in a '\' */
- fname_len = strlen(fname);
if (fname_len > 0 && fname[fname_len-1] == '\\') {
char *new_fname = talloc_strdup(state, fname);
if (tevent_req_nomem(new_fname, req)) {
@@ -225,7 +266,7 @@ struct tevent_req *cli_smb2_create_fnum_send(TALLOC_CTX *mem_ctx,
share_access,
create_disposition,
create_options,
- NULL);
+ cblobs);
if (tevent_req_nomem(subreq, req)) {
return tevent_req_post(req, ev);
}
--
2.8.0.rc3.226.g39d4020
More information about the samba-technical
mailing list