[PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient.

classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

[PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient.

Samba - samba-technical mailing list
Latest part of my quest to get a working test environment
for reparse points so I can implement them in smbd.

This patchset fixes up the code in libsmb/clisymlink.c
and libsmb/cli_smb2_fnum.c to be able to do async
reparse point get/set.

I've tested against Windows (which is currently the
best I can do). Once this goes in I can start using
this to create smbtorture tests against smbd with
an implementation of storing reparse points inside
extended attributes on files/directories.

Please review and push if happy !

Cheers,

        Jeremy.

bug-13159.master (26K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient.

Samba - samba-technical mailing list
On Wed, Nov 29, 2017 at 03:22:40PM -0800, Jeremy Allison via samba-technical wrote:

> Latest part of my quest to get a working test environment
> for reparse points so I can implement them in smbd.
>
> This patchset fixes up the code in libsmb/clisymlink.c
> and libsmb/cli_smb2_fnum.c to be able to do async
> reparse point get/set.
>
> I've tested against Windows (which is currently the
> best I can do). Once this goes in I can start using
> this to create smbtorture tests against smbd with
> an implementation of storing reparse points inside
> extended attributes on files/directories.

> +static void cli_close_done(struct tevent_req *subreq)
> +{
> + struct tevent_req *req = tevent_req_callback_data(
> + subreq, struct tevent_req);
> + NTSTATUS status = tevent_req_simple_recv_ntstatus(subreq);

Please don't call tevent_req_simple_recv_ntstatus directly from a
_done routine, please create a wrapper for it. It might be idempotent,
but it is this kind of confusion around this routine that for example
caused the valgrind error you just fixed.

Maybe it's better to just remove this obviously very misleading
function and expand it into all its users. Do you want me to do this
to avoid this kind of discussion in the future? I can probably pretty
quickly get this patch done to remove this flawed abstraction.

Volker

--
SerNet GmbH, Bahnhofsallee 1b, 37081 Göttingen
phone: +49-551-370000-0, fax: +49-551-370000-9
AG Göttingen, HRB 2816, GF: Dr. Johannes Loxen
http://www.sernet.de, mailto:[hidden email]

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient.

Samba - samba-technical mailing list
On Thu, Nov 30, 2017 at 12:48:01PM +0100, Volker Lendecke wrote:

> On Wed, Nov 29, 2017 at 03:22:40PM -0800, Jeremy Allison via samba-technical wrote:
> > Latest part of my quest to get a working test environment
> > for reparse points so I can implement them in smbd.
> >
> > This patchset fixes up the code in libsmb/clisymlink.c
> > and libsmb/cli_smb2_fnum.c to be able to do async
> > reparse point get/set.
> >
> > I've tested against Windows (which is currently the
> > best I can do). Once this goes in I can start using
> > this to create smbtorture tests against smbd with
> > an implementation of storing reparse points inside
> > extended attributes on files/directories.
>
> > +static void cli_close_done(struct tevent_req *subreq)
> > +{
> > + struct tevent_req *req = tevent_req_callback_data(
> > + subreq, struct tevent_req);
> > + NTSTATUS status = tevent_req_simple_recv_ntstatus(subreq);
>
> Please don't call tevent_req_simple_recv_ntstatus directly from a
> _done routine, please create a wrapper for it. It might be idempotent,
> but it is this kind of confusion around this routine that for example
> caused the valgrind error you just fixed.
>
> Maybe it's better to just remove this obviously very misleading
> function and expand it into all its users. Do you want me to do this
> to avoid this kind of discussion in the future? I can probably pretty
> quickly get this patch done to remove this flawed abstraction.

OK, thanks for the feedback. I'll correct this and
post an updated patch soon.

Cheers,

Jeremy.

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient.

Samba - samba-technical mailing list
In reply to this post by Samba - samba-technical mailing list
On Thu, Nov 30, 2017 at 12:48:01PM +0100, Volker Lendecke wrote:

> On Wed, Nov 29, 2017 at 03:22:40PM -0800, Jeremy Allison via samba-technical wrote:
> > Latest part of my quest to get a working test environment
> > for reparse points so I can implement them in smbd.
> >
> > This patchset fixes up the code in libsmb/clisymlink.c
> > and libsmb/cli_smb2_fnum.c to be able to do async
> > reparse point get/set.
> >
> > I've tested against Windows (which is currently the
> > best I can do). Once this goes in I can start using
> > this to create smbtorture tests against smbd with
> > an implementation of storing reparse points inside
> > extended attributes on files/directories.
>
> > +static void cli_close_done(struct tevent_req *subreq)
> > +{
> > + struct tevent_req *req = tevent_req_callback_data(
> > + subreq, struct tevent_req);
> > + NTSTATUS status = tevent_req_simple_recv_ntstatus(subreq);
>
> Please don't call tevent_req_simple_recv_ntstatus directly from a
> _done routine, please create a wrapper for it. It might be idempotent,
> but it is this kind of confusion around this routine that for example
> caused the valgrind error you just fixed.
>
> Maybe it's better to just remove this obviously very misleading
> function and expand it into all its users. Do you want me to do this
> to avoid this kind of discussion in the future? I can probably pretty
> quickly get this patch done to remove this flawed abstraction.
No, I think the abstraction is good - but maybe I'll add
a later patch that that explains canonical use of it (if
you're review of course). It really is a useful bit of
code if used correctly.

Anyway, here is a corrected patch that (hopefully)
uses the tevent_req_simple_XXX() abstractions correctly
(i.e. I removed it from cli_close_done() which I think
was the only place I'd screwed it up).

I've tested here and it works. Volker or Ralph, please
review and push if happy !

Thanks,

        Jeremy.

bug-13159-master (26K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient.

Samba - samba-technical mailing list
In reply to this post by Samba - samba-technical mailing list
On 11/29/2017 04:22 PM, Jeremy Allison via samba-technical wrote:
> Latest part of my quest to get a working test environment
> for reparse points so I can implement them in smbd.

Jacob Holtom and I have been working on the smbd symlink reparse point
code as well, changing it to properly return the symlink error/reparse
responses instead of just adding the reparse tag.

Our target environment does not support extended attributes.  We've been
talking about using the UNIX symlink target as the link-target when the
follow symlinks option is enabled.  Does anyone have any objections?

Daniel


Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient.

Samba - samba-technical mailing list
On Fri, Dec 01, 2017 at 09:34:10AM -0700, Daniel Fussell via samba-technical wrote:

> On 11/29/2017 04:22 PM, Jeremy Allison via samba-technical wrote:
> > Latest part of my quest to get a working test environment
> > for reparse points so I can implement them in smbd.
>
> Jacob Holtom and I have been working on the smbd symlink reparse point
> code as well, changing it to properly return the symlink error/reparse
> responses instead of just adding the reparse tag.
>
> Our target environment does not support extended attributes.  We've been
> talking about using the UNIX symlink target as the link-target when the
> follow symlinks option is enabled.  Does anyone have any objections?

Yes, I don't want smbd creating UNIX symlinks anymore.

This has been and continues to be a big security hole.

I only want reparse points stored in EA's.

Jeremy.

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient.

Samba - samba-technical mailing list
On Fri, Dec 01, 2017 at 09:11:37AM -0800, Jeremy Allison via samba-technical wrote:

> On Fri, Dec 01, 2017 at 09:34:10AM -0700, Daniel Fussell via samba-technical wrote:
> > On 11/29/2017 04:22 PM, Jeremy Allison via samba-technical wrote:
> > > Latest part of my quest to get a working test environment
> > > for reparse points so I can implement them in smbd.
> >
> > Jacob Holtom and I have been working on the smbd symlink reparse point
> > code as well, changing it to properly return the symlink error/reparse
> > responses instead of just adding the reparse tag.
> >
> > Our target environment does not support extended attributes.  We've been
> > talking about using the UNIX symlink target as the link-target when the
> > follow symlinks option is enabled.  Does anyone have any objections?
>
> Yes, I don't want smbd creating UNIX symlinks anymore.
>
> This has been and continues to be a big security hole.
>
> I only want reparse points stored in EA's.

Expaning further. At least on Linux you can't store
EA's on symlinks. This means you have nowhere to store
the FILE_ATTRIBUTE_REPARSE_POINT bit, and will have
to expose *all* symlinks on the server filesystem as
reparse points.

This is a receipe for disaster. Please don't do this :-).

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient.

Samba - samba-technical mailing list
In reply to this post by Samba - samba-technical mailing list
On 12/01/2017 10:11 AM, Jeremy Allison via samba-technical wrote:

> On Fri, Dec 01, 2017 at 09:34:10AM -0700, Daniel Fussell via samba-technical wrote:
>> On 11/29/2017 04:22 PM, Jeremy Allison via samba-technical wrote:
>>> Latest part of my quest to get a working test environment
>>> for reparse points so I can implement them in smbd.
>> Jacob Holtom and I have been working on the smbd symlink reparse point
>> code as well, changing it to properly return the symlink error/reparse
>> responses instead of just adding the reparse tag.
>>
>> Our target environment does not support extended attributes.  We've been
>> talking about using the UNIX symlink target as the link-target when the
>> follow symlinks option is enabled.  Does anyone have any objections?
> Yes, I don't want smbd creating UNIX symlinks anymore.
>
> This has been and continues to be a big security hole.
>
> I only want reparse points stored in EA's.
>
> Jeremy.
>

I'm assuming the big security hole is largely TOCTTOU races and/or wide
links.  If there's more to it, please enlighten me.

If I understand correctly, you want reparse point flags stored in the EA
only, so the server cannot follow it, period.  If the target isn't in
the share, resolvable by the client, you can't get there from here. 
It's also easier to code, no doubt.  Am I understanding correctly?

My problem with the EA-only approach is it breaks expected behavior on
multi-protocol filers (and the local filesystem).  If I create a
symlink, I want the symlink to work the same regardless of the protocol
involved.

I think we can have our SMB2 symlinks and protect them too.  I'm not
suggesting we ignore security, so bear with me a moment. 

I propose we do the following:

 1. Limit creation of SMB2 symlinks to "admin list" users only.  That
    should resolve most of the symlink security problems, and is the
    recommendation for a windows box anyway:
    https://technet.microsoft.com/en-us/library/dn221947(v=ws.11).aspx
 2. If the SMB2 symlink is created by a trusted admin, create it as a
    trusted (or maybe user) EA on a file, just as you originally decided. 
     1. The trusted admins know what they want.  If they want a
        Windows-only traversable symlink resolved only by the client,
        they should be able to have it.
     2. The trusted admins can also create the Windows-only EA-based
        link on the server-side shell with setfattr.  This would allow
        setting other attributes/reparse-tags  for the other
        reparse-point types (HSM, DFS, user-defined values, etc) if such
        ever proves useful.
 3. If the file is a UNIX symlink that points to a wide-link target and
    options are enabled for wide links and follow symlinks, return an
    SMB2 symlink error with IO_REPARSE_TAG_MOUNT_POINT, so the client
    knows it is a server-resolved target, and it's free space
    information must be re-queried.


Item 3 is probably not perfect, but we are doing some exploratory coding
on it now to see if such a thing would be agreeable to the client.  I
think it would resolve the symlink disaster of two round trips to
resolve every symlink.

Our previous patch submission tried to add just
IO_REPARSE_TAG_MOUNT_POINT support in a general, non-protocol-dependent
way.  The logic was subtlety flawed, and I don't think the symlink error
struct was returned.  I think the general case handling would be better,
but a more agreeable way of detecting the mount-point crossing would be
needed.

Where the SMB2/FSCC symlink error struct handles both SMB2 symlinks and
mountpoint tags, they should probably be implemented together.

Comments welcome.
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient.

Samba - samba-technical mailing list
In reply to this post by Samba - samba-technical mailing list
On Thu, Nov 30, 2017 at 04:29:42PM -0800, Jeremy Allison wrote:

> On Thu, Nov 30, 2017 at 12:48:01PM +0100, Volker Lendecke wrote:
> > On Wed, Nov 29, 2017 at 03:22:40PM -0800, Jeremy Allison via samba-technical wrote:
> > > Latest part of my quest to get a working test environment
> > > for reparse points so I can implement them in smbd.
> > >
> > > This patchset fixes up the code in libsmb/clisymlink.c
> > > and libsmb/cli_smb2_fnum.c to be able to do async
> > > reparse point get/set.
> > >
> > > I've tested against Windows (which is currently the
> > > best I can do). Once this goes in I can start using
> > > this to create smbtorture tests against smbd with
> > > an implementation of storing reparse points inside
> > > extended attributes on files/directories.
> >
> > > +static void cli_close_done(struct tevent_req *subreq)
> > > +{
> > > + struct tevent_req *req = tevent_req_callback_data(
> > > + subreq, struct tevent_req);
> > > + NTSTATUS status = tevent_req_simple_recv_ntstatus(subreq);
> >
> > Please don't call tevent_req_simple_recv_ntstatus directly from a
> > _done routine, please create a wrapper for it. It might be idempotent,
> > but it is this kind of confusion around this routine that for example
> > caused the valgrind error you just fixed.
> >
> > Maybe it's better to just remove this obviously very misleading
> > function and expand it into all its users. Do you want me to do this
> > to avoid this kind of discussion in the future? I can probably pretty
> > quickly get this patch done to remove this flawed abstraction.
>
> No, I think the abstraction is good - but maybe I'll add
> a later patch that that explains canonical use of it (if
> you're review of course). It really is a useful bit of
> code if used correctly.
>
> Anyway, here is a corrected patch that (hopefully)
> uses the tevent_req_simple_XXX() abstractions correctly
> (i.e. I removed it from cli_close_done() which I think
> was the only place I'd screwed it up).
>
> I've tested here and it works. Volker or Ralph, please
> review and push if happy !


Ralph, ping ! Can you take a look please ? I'd like this
in place so I can start on my smbtorture Windows reparse
points full tests.

Thanks !

Jeremy.

> From f082659a2b9a58c2ccef4a1cacc9efa9fd870c7b Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Wed, 22 Nov 2017 00:47:48 +0000
> Subject: [PATCH 1/7] s3: libsmb: Rename cli_close_create() ->
>  cli_smb1_close_create().
>
> Move cli_smb1_close_done() next to its caller. This is SMB1 specific.
> Prepare to wrap cli_close_send/cli_close_recv to handle SMB2.
>
> BUG: https://bugzilla.samba.org/show_bug.cgi?id=13159
>
> Signed-off-by: Jeremy Allison <[hidden email]>
> ---
>  source3/libsmb/clifile.c      | 42 +++++++++++++++++++++---------------------
>  source3/libsmb/proto.h        |  2 +-
>  source3/torture/test_chain3.c |  2 +-
>  source3/torture/torture.c     |  2 +-
>  4 files changed, 24 insertions(+), 24 deletions(-)
>
> diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
> index e942b27e175..2e3c2426030 100644
> --- a/source3/libsmb/clifile.c
> +++ b/source3/libsmb/clifile.c
> @@ -2770,22 +2770,22 @@ NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags,
>   Close a file.
>  ****************************************************************************/
>  
> -struct cli_close_state {
> +struct cli_smb1_close_state {
>   uint16_t vwv[3];
>  };
>  
> -static void cli_close_done(struct tevent_req *subreq);
> +static void cli_smb1_close_done(struct tevent_req *subreq);
>  
> -struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
> +struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
>   struct tevent_context *ev,
>   struct cli_state *cli,
>   uint16_t fnum,
>   struct tevent_req **psubreq)
>  {
>   struct tevent_req *req, *subreq;
> - struct cli_close_state *state;
> + struct cli_smb1_close_state *state;
>  
> - req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
> + req = tevent_req_create(mem_ctx, &state, struct cli_smb1_close_state);
>   if (req == NULL) {
>   return NULL;
>   }
> @@ -2799,11 +2799,25 @@ struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
>   TALLOC_FREE(req);
>   return NULL;
>   }
> - tevent_req_set_callback(subreq, cli_close_done, req);
> + tevent_req_set_callback(subreq, cli_smb1_close_done, req);
>   *psubreq = subreq;
>   return req;
>  }
>  
> +static void cli_smb1_close_done(struct tevent_req *subreq)
> +{
> + struct tevent_req *req = tevent_req_callback_data(
> + subreq, struct tevent_req);
> + NTSTATUS status;
> +
> + status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
> + TALLOC_FREE(subreq);
> + if (tevent_req_nterror(req, status)) {
> + return;
> + }
> + tevent_req_done(req);
> +}
> +
>  struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
>   struct tevent_context *ev,
>   struct cli_state *cli,
> @@ -2812,7 +2826,7 @@ struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
>   struct tevent_req *req, *subreq;
>   NTSTATUS status;
>  
> - req = cli_close_create(mem_ctx, ev, cli, fnum, &subreq);
> + req = cli_smb1_close_create(mem_ctx, ev, cli, fnum, &subreq);
>   if (req == NULL) {
>   return NULL;
>   }
> @@ -2824,20 +2838,6 @@ struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
>   return req;
>  }
>  
> -static void cli_close_done(struct tevent_req *subreq)
> -{
> - struct tevent_req *req = tevent_req_callback_data(
> - subreq, struct tevent_req);
> - NTSTATUS status;
> -
> - status = cli_smb_recv(subreq, NULL, NULL, 0, NULL, NULL, NULL, NULL);
> - TALLOC_FREE(subreq);
> - if (tevent_req_nterror(req, status)) {
> - return;
> - }
> - tevent_req_done(req);
> -}
> -
>  NTSTATUS cli_close_recv(struct tevent_req *req)
>  {
>   return tevent_req_simple_recv_ntstatus(req);
> diff --git a/source3/libsmb/proto.h b/source3/libsmb/proto.h
> index 4ae566cca1c..d82de56a238 100644
> --- a/source3/libsmb/proto.h
> +++ b/source3/libsmb/proto.h
> @@ -423,7 +423,7 @@ struct tevent_req *cli_openx_send(TALLOC_CTX *mem_ctx, struct tevent_context *ev
>  NTSTATUS cli_openx_recv(struct tevent_req *req, uint16_t *fnum);
>  NTSTATUS cli_openx(struct cli_state *cli, const char *fname, int flags, int share_mode, uint16_t *pfnum);
>  NTSTATUS cli_open(struct cli_state *cli, const char *fname, int flags, int share_mode, uint16_t *pfnum);
> -struct tevent_req *cli_close_create(TALLOC_CTX *mem_ctx,
> +struct tevent_req *cli_smb1_close_create(TALLOC_CTX *mem_ctx,
>      struct tevent_context *ev,
>      struct cli_state *cli, uint16_t fnum,
>      struct tevent_req **psubreq);
> diff --git a/source3/torture/test_chain3.c b/source3/torture/test_chain3.c
> index cad1a3fb407..eff39de8702 100644
> --- a/source3/torture/test_chain3.c
> +++ b/source3/torture/test_chain3.c
> @@ -70,7 +70,7 @@ static struct tevent_req *chain3_andx_send(TALLOC_CTX *mem_ctx,
>   }
>   tevent_req_set_callback(subreq, chain3_andx_write_done, req);
>  
> - subreq = cli_close_create(state, ev, cli, 0, &smbreqs[2]);
> + subreq = cli_smb1_close_create(state, ev, cli, 0, &smbreqs[2]);
>   if (tevent_req_nomem(subreq, req)) {
>   return tevent_req_post(req, ev);
>   }
> diff --git a/source3/torture/torture.c b/source3/torture/torture.c
> index cf8b03ca111..87276c09cb3 100644
> --- a/source3/torture/torture.c
> +++ b/source3/torture/torture.c
> @@ -8066,7 +8066,7 @@ static bool run_chain1(int dummy)
>   if (reqs[1] == NULL) return false;
>   tevent_req_set_callback(reqs[1], chain1_write_completion, NULL);
>  
> - reqs[2] = cli_close_create(talloc_tos(), evt, cli1, 0, &smbreqs[2]);
> + reqs[2] = cli_smb1_close_create(talloc_tos(), evt, cli1, 0, &smbreqs[2]);
>   if (reqs[2] == NULL) return false;
>   tevent_req_set_callback(reqs[2], chain1_close_completion, &done);
>  
> --
> 2.15.0.531.g2ccb3012c9-goog
>
>
> From 8d5774eb888aee08f4ed2c3a13771b9dc86473b1 Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Mon, 27 Nov 2017 14:38:49 -0800
> Subject: [PATCH 2/7] s3: libsmb: Make cli_close_send()/cli_close_recv() work
>  for SMB1 and SMB2.
>
> Remove the escape into synchronous smb2 code.
>
> BUG: https://bugzilla.samba.org/show_bug.cgi?id=13159
>
> Signed-off-by: Jeremy Allison <[hidden email]>
> ---
>  source3/libsmb/clifile.c | 51 ++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 43 insertions(+), 8 deletions(-)
>
> diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
> index 2e3c2426030..b0a2759ecf8 100644
> --- a/source3/libsmb/clifile.c
> +++ b/source3/libsmb/clifile.c
> @@ -2818,26 +2818,65 @@ static void cli_smb1_close_done(struct tevent_req *subreq)
>   tevent_req_done(req);
>  }
>  
> +struct cli_close_state {
> + int dummy;
> +};
> +
> +static void cli_close_done(struct tevent_req *subreq);
> +
>  struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
>   struct tevent_context *ev,
>   struct cli_state *cli,
>   uint16_t fnum)
>  {
>   struct tevent_req *req, *subreq;
> + struct cli_close_state *state;
>   NTSTATUS status;
>  
> - req = cli_smb1_close_create(mem_ctx, ev, cli, fnum, &subreq);
> + req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
>   if (req == NULL) {
>   return NULL;
>   }
>  
> - status = smb1cli_req_chain_submit(&subreq, 1);
> - if (tevent_req_nterror(req, status)) {
> - return tevent_req_post(req, ev);
> + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
> + subreq = cli_smb2_close_fnum_send(mem_ctx,
> + ev,
> + cli,
> + fnum);
> + if (tevent_req_nomem(subreq, req)) {
> + return tevent_req_post(req, ev);
> + }
> + } else {
> + struct tevent_req *ch_req = NULL;
> + subreq = cli_smb1_close_create(mem_ctx, ev, cli, fnum, &ch_req);
> + if (tevent_req_nomem(subreq, req)) {
> + return tevent_req_post(req, ev);
> + }
> + status = smb1cli_req_chain_submit(&ch_req, 1);
> + if (tevent_req_nterror(req, status)) {
> + return tevent_req_post(req, ev);
> + }
>   }
> +
> + tevent_req_set_callback(subreq, cli_close_done, req);
>   return req;
>  }
>  
> +static void cli_close_done(struct tevent_req *subreq)
> +{
> + struct tevent_req *req = tevent_req_callback_data(
> + subreq, struct tevent_req);
> + NTSTATUS status = NT_STATUS_OK;
> + bool err = tevent_req_is_nterror(subreq, &status);
> +
> + TALLOC_FREE(subreq);
> + if (err) {
> + tevent_req_nterror(req, status);
> + return;
> + }
> + tevent_req_done(req);
> +}
> +
>  NTSTATUS cli_close_recv(struct tevent_req *req)
>  {
>   return tevent_req_simple_recv_ntstatus(req);
> @@ -2850,10 +2889,6 @@ NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
>   struct tevent_req *req;
>   NTSTATUS status = NT_STATUS_OK;
>  
> - if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
> - return cli_smb2_close_fnum(cli, fnum);
> - }
> -
>   frame = talloc_stackframe();
>  
>   if (smbXcli_conn_has_async_calls(cli->conn)) {
> --
> 2.15.0.531.g2ccb3012c9-goog
>
>
> From faf81a560bcbaeab3ae0f32f5446716ec10179f1 Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Tue, 28 Nov 2017 14:09:39 -0800
> Subject: [PATCH 3/7] s3: libsmb: Add SMB2 calls
>  cli_smb2_set_reparse_point_fnum_send()/cli_smb2_set_reparse_point_fnum_recv().
>
> Allow reparse points to be created over SMB2.
>
> BUG: https://bugzilla.samba.org/show_bug.cgi?id=13159
>
> Signed-off-by: Jeremy Allison <[hidden email]>
> ---
>  source3/libsmb/cli_smb2_fnum.c | 93 ++++++++++++++++++++++++++++++++++++++++++
>  source3/libsmb/cli_smb2_fnum.h |  8 ++++
>  2 files changed, 101 insertions(+)
>
> diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
> index 78f61fbedd4..f8861e53345 100644
> --- a/source3/libsmb/cli_smb2_fnum.c
> +++ b/source3/libsmb/cli_smb2_fnum.c
> @@ -4181,3 +4181,96 @@ fail:
>   TALLOC_FREE(frame);
>   return status;
>  }
> +
> +struct cli_smb2_set_reparse_point_fnum_state {
> + struct cli_state *cli;
> + uint16_t fnum;
> + struct smb2_hnd *ph;
> + DATA_BLOB input_buffer;
> +};
> +
> +static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq);
> +
> +struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
> + TALLOC_CTX *mem_ctx,
> + struct tevent_context *ev,
> + struct cli_state *cli,
> + uint16_t fnum,
> + DATA_BLOB in_buf)
> +{
> + struct tevent_req *req, *subreq;
> + struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
> + NTSTATUS status;
> +
> + req = tevent_req_create(mem_ctx, &state,
> + struct cli_smb2_set_reparse_point_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);
> + }
> +
> + state->input_buffer = data_blob_talloc(state,
> + in_buf.data,
> + in_buf.length);
> + if (state->input_buffer.data == NULL) {
> + tevent_req_nterror(req, NT_STATUS_NO_MEMORY);
> + return tevent_req_post(req, ev);
> + }
> +
> + 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_SET_REPARSE_POINT,
> + 0, /* in_max_input_length */
> + &state->input_buffer ,
> + 0,
> + NULL,
> + SMB2_IOCTL_FLAG_IS_FSCTL);
> +
> + if (tevent_req_nomem(subreq, req)) {
> + return tevent_req_post(req, ev);
> + }
> + tevent_req_set_callback(subreq,
> + cli_smb2_set_reparse_point_fnum_done,
> + req);
> +
> + return req;
> +}
> +
> +static void cli_smb2_set_reparse_point_fnum_done(struct tevent_req *subreq)
> +{
> + struct tevent_req *req = tevent_req_callback_data(
> + subreq, struct tevent_req);
> + struct cli_smb2_set_reparse_point_fnum_state *state = tevent_req_data(
> + req, struct cli_smb2_set_reparse_point_fnum_state);
> + NTSTATUS status;
> +
> + status = smb2cli_ioctl_recv(subreq, state,
> + NULL,
> + NULL);
> + TALLOC_FREE(subreq);
> + if (tevent_req_nterror(req, status)) {
> + return;
> + }
> + tevent_req_done(req);
> +}
> +
> +NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
> +{
> +        return tevent_req_simple_recv_ntstatus(req);
> +}
> diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
> index 3d9b6eb3fe6..0f6809fe4ca 100644
> --- a/source3/libsmb/cli_smb2_fnum.h
> +++ b/source3/libsmb/cli_smb2_fnum.h
> @@ -242,4 +242,12 @@ NTSTATUS cli_smb2_notify(struct cli_state *cli, uint16_t fnum,
>   bool recursive, TALLOC_CTX *mem_ctx,
>   struct notify_change **pchanges,
>   uint32_t *pnum_changes);
> +struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
> + TALLOC_CTX *mem_ctx,
> + struct tevent_context *ev,
> + struct cli_state *cli,
> + uint16_t fnum,
> + DATA_BLOB in_buf);
> +NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req);
> +
>  #endif /* __SMB2CLI_FNUM_H__ */
> --
> 2.15.0.531.g2ccb3012c9-goog
>
>
> From 8bae632bf7bd53f1858fe206abf21290fa901367 Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Tue, 28 Nov 2017 14:10:26 -0800
> Subject: [PATCH 4/7] s3: libsmb: Plumb in the new SMB2 reparse point calls
>  into the cli_symlink_create_XXX() calls.
>
> Reparse point symlinks can now be created over SMB1 and SMB2 from
> smbclient.
>
> BUG: https://bugzilla.samba.org/show_bug.cgi?id=13159
>
> Signed-off-by: Jeremy Allison <[hidden email]>
> ---
>  source3/libsmb/clisymlink.c | 45 ++++++++++++++++++++++++++++++---------------
>  1 file changed, 30 insertions(+), 15 deletions(-)
>
> diff --git a/source3/libsmb/clisymlink.c b/source3/libsmb/clisymlink.c
> index a52f6ff7f6d..202435722c9 100644
> --- a/source3/libsmb/clisymlink.c
> +++ b/source3/libsmb/clisymlink.c
> @@ -86,8 +86,7 @@ static void cli_symlink_create_done(struct tevent_req *subreq)
>   subreq, struct tevent_req);
>   struct cli_symlink_state *state = tevent_req_data(
>   req, struct cli_symlink_state);
> - uint8_t *data;
> - size_t data_len;
> + DATA_BLOB data;
>   NTSTATUS status;
>  
>   status = cli_ntcreate_recv(subreq, &state->fnum, NULL);
> @@ -96,24 +95,35 @@ static void cli_symlink_create_done(struct tevent_req *subreq)
>   return;
>   }
>  
> - SIVAL(state->setup, 0, FSCTL_SET_REPARSE_POINT);
> - SSVAL(state->setup, 4, state->fnum);
> - SCVAL(state->setup, 6, 1); /* IsFcntl */
> - SCVAL(state->setup, 7, 0); /* IsFlags */
> -
>   if (!symlink_reparse_buffer_marshall(
>      state->link_target, NULL, state->flags, state,
> -    &data, &data_len)) {
> +    &data.data, &data.length)) {
>   tevent_req_oom(req);
>   return;
>   }
>  
> - subreq = cli_trans_send(state, state->ev, state->cli, 0, SMBnttrans,
> + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
> + subreq = cli_smb2_set_reparse_point_fnum_send(state,
> + state->ev,
> + state->cli,
> + state->fnum,
> + data);
> + } else {
> + SIVAL(state->setup, 0, FSCTL_SET_REPARSE_POINT);
> + SSVAL(state->setup, 4, state->fnum);
> + SCVAL(state->setup, 6, 1); /* IsFcntl */
> + SCVAL(state->setup, 7, 0); /* IsFlags */
> +
> +
> + subreq = cli_trans_send(state, state->ev, state->cli, 0,
> + SMBnttrans,
>   NULL, -1, /* name, fid */
>   NT_TRANSACT_IOCTL, 0,
>   state->setup, 4, 0, /* setup */
>   NULL, 0, 0,    /* param */
> - data, data_len, 0); /* data */
> + data.data, data.length, 0); /* data */
> + }
> +
>   if (tevent_req_nomem(subreq, req)) {
>   return;
>   }
> @@ -127,11 +137,16 @@ static void cli_symlink_set_reparse_done(struct tevent_req *subreq)
>   struct cli_symlink_state *state = tevent_req_data(
>   req, struct cli_symlink_state);
>  
> - state->set_reparse_status = cli_trans_recv(
> - subreq, NULL, NULL,
> - NULL, 0, NULL, /* rsetup */
> - NULL, 0, NULL, /* rparam */
> - NULL, 0, NULL); /* rdata */
> + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
> + state->set_reparse_status =
> + cli_smb2_set_reparse_point_fnum_recv(subreq);
> + } else {
> + state->set_reparse_status = cli_trans_recv(
> + subreq, NULL, NULL,
> + NULL, 0, NULL, /* rsetup */
> + NULL, 0, NULL, /* rparam */
> + NULL, 0, NULL); /* rdata */
> + }
>   TALLOC_FREE(subreq);
>  
>   if (NT_STATUS_IS_OK(state->set_reparse_status)) {
> --
> 2.15.0.531.g2ccb3012c9-goog
>
>
> From 5eadea9e7cc14ab3d9ebac268ad27b4b089bceef Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Tue, 28 Nov 2017 15:46:40 -0800
> Subject: [PATCH 5/7] s3: libsmb: Do a naive response to SMB2 "stopped on
>  symlink". Assume the last component was the reparse point.
>
> Attempt re-open with FILE_OPEN_REPARSE_POINT. This matches the SMB1
> behavior for smbclient.
>
> BUG: https://bugzilla.samba.org/show_bug.cgi?id=13159
>
> Signed-off-by: Jeremy Allison <[hidden email]>
> ---
>  source3/libsmb/cli_smb2_fnum.c | 65 +++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 64 insertions(+), 1 deletion(-)
>
> diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
> index f8861e53345..c40d6dd3a45 100644
> --- a/source3/libsmb/cli_smb2_fnum.c
> +++ b/source3/libsmb/cli_smb2_fnum.c
> @@ -686,6 +686,27 @@ NTSTATUS cli_smb2_rmdir(struct cli_state *cli, const char *dname)
>   &fnum,
>   NULL);
>  
> + if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
> + /*
> + * Naive option to match our SMB1 code. Assume the
> + * symlink path that tripped us up was the last
> + * component and try again. Eventually we will have to
> + * deal with the returned path unprocessed component. JRA.
> + */
> + status = cli_smb2_create_fnum(cli,
> + dname,
> + 0, /* create_flags */
> + DELETE_ACCESS, /* desired_access */
> + FILE_ATTRIBUTE_DIRECTORY, /* file attributes */
> + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
> + FILE_OPEN, /* create_disposition */
> + FILE_DIRECTORY_FILE|
> + FILE_DELETE_ON_CLOSE|
> + FILE_OPEN_REPARSE_POINT, /* create_options */
> + &fnum,
> + NULL);
> + }
> +
>   if (!NT_STATUS_IS_OK(status)) {
>   return status;
>   }
> @@ -724,6 +745,26 @@ NTSTATUS cli_smb2_unlink(struct cli_state *cli, const char *fname)
>   &fnum,
>   NULL);
>  
> + if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
> + /*
> + * Naive option to match our SMB1 code. Assume the
> + * symlink path that tripped us up was the last
> + * component and try again. Eventually we will have to
> + * deal with the returned path unprocessed component. JRA.
> + */
> + status = cli_smb2_create_fnum(cli,
> + fname,
> + 0, /* create_flags */
> + DELETE_ACCESS, /* desired_access */
> + FILE_ATTRIBUTE_NORMAL, /* file attributes */
> + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
> + FILE_OPEN, /* create_disposition */
> + FILE_DELETE_ON_CLOSE|
> + FILE_OPEN_REPARSE_POINT, /* create_options */
> + &fnum,
> + NULL);
> + }
> +
>   if (!NT_STATUS_IS_OK(status)) {
>   return status;
>   }
> @@ -1157,6 +1198,7 @@ static NTSTATUS get_fnum_from_path(struct cli_state *cli,
>   NTSTATUS status;
>   size_t namelen = strlen(name);
>   TALLOC_CTX *frame = talloc_stackframe();
> + uint32_t create_options = 0;
>  
>   /* SMB2 is pickier about pathnames. Ensure it doesn't
>     end in a '\' */
> @@ -1178,11 +1220,32 @@ static NTSTATUS get_fnum_from_path(struct cli_state *cli,
>   0, /* file attributes */
>   FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
>   FILE_OPEN, /* create_disposition */
> - 0, /* create_options */
> + create_options,
> + pfnum,
> + NULL);
> +
> + if (NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) {
> + /*
> + * Naive option to match our SMB1 code. Assume the
> + * symlink path that tripped us up was the last
> + * component and try again. Eventually we will have to
> + * deal with the returned path unprocessed component. JRA.
> + */
> + create_options |= FILE_OPEN_REPARSE_POINT;
> + status = cli_smb2_create_fnum(cli,
> + name,
> + 0, /* create_flags */
> + desired_access,
> + 0, /* file attributes */
> + FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE, /* share_access */
> + FILE_OPEN, /* create_disposition */
> + create_options,
>   pfnum,
>   NULL);
> + }
>  
>   if (NT_STATUS_EQUAL(status, NT_STATUS_FILE_IS_A_DIRECTORY)) {
> + create_options |= FILE_DIRECTORY_FILE;
>   status = cli_smb2_create_fnum(cli,
>   name,
>   0, /* create_flags */
> --
> 2.15.0.531.g2ccb3012c9-goog
>
>
> From 328229e2fe6a344f895baa47147c1f1aa5c1e2d4 Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Wed, 29 Nov 2017 12:37:36 -0800
> Subject: [PATCH 6/7] s3: libsmb: Add SMB2 calls
>  cli_smb2_get_reparse_point_fnum_send()/cli_smb2_get_reparse_point_fnum_recv().
>
> Allow reparse points to be queried over SMB2.
>
> BUG: https://bugzilla.samba.org/show_bug.cgi?id=13159
>
> Signed-off-by: Jeremy Allison <[hidden email]>
> ---
>  source3/libsmb/cli_smb2_fnum.c | 96 ++++++++++++++++++++++++++++++++++++++++++
>  source3/libsmb/cli_smb2_fnum.h |  9 ++++
>  2 files changed, 105 insertions(+)
>
> diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
> index c40d6dd3a45..a54c248720b 100644
> --- a/source3/libsmb/cli_smb2_fnum.c
> +++ b/source3/libsmb/cli_smb2_fnum.c
> @@ -4337,3 +4337,99 @@ NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
>  {
>          return tevent_req_simple_recv_ntstatus(req);
>  }
> +
> +struct cli_smb2_get_reparse_point_fnum_state {
> + struct cli_state *cli;
> + uint16_t fnum;
> + struct smb2_hnd *ph;
> + DATA_BLOB output_buffer;
> +};
> +
> +static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
> +
> +struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
> + TALLOC_CTX *mem_ctx,
> + struct tevent_context *ev,
> + struct cli_state *cli,
> + uint16_t fnum)
> +{
> + struct tevent_req *req, *subreq;
> + struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
> + NTSTATUS status;
> +
> + req = tevent_req_create(mem_ctx, &state,
> + struct cli_smb2_get_reparse_point_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);
> + }
> +
> + 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_REPARSE_POINT,
> + 0, /* in_max_input_length */
> + NULL,
> + 64*1024,
> + NULL,
> + SMB2_IOCTL_FLAG_IS_FSCTL);
> +
> + if (tevent_req_nomem(subreq, req)) {
> + return tevent_req_post(req, ev);
> + }
> + tevent_req_set_callback(subreq,
> + cli_smb2_get_reparse_point_fnum_done,
> + req);
> +
> + return req;
> +}
> +
> +static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
> +{
> + struct tevent_req *req = tevent_req_callback_data(
> + subreq, struct tevent_req);
> + struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
> + req, struct cli_smb2_get_reparse_point_fnum_state);
> + NTSTATUS status;
> +
> + status = smb2cli_ioctl_recv(subreq, state,
> + NULL,
> + &state->output_buffer);
> + TALLOC_FREE(subreq);
> + if (tevent_req_nterror(req, status)) {
> + return;
> + }
> + tevent_req_done(req);
> +}
> +
> +NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
> + TALLOC_CTX *mem_ctx,
> + DATA_BLOB *output)
> +{
> + struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
> + req, struct cli_smb2_get_reparse_point_fnum_state);
> +
> + if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
> + return state->cli->raw_status;
> + }
> + *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);
> + if (output->data == NULL) {
> + return NT_STATUS_NO_MEMORY;
> + }
> + return NT_STATUS_OK;
> +}
> diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
> index 0f6809fe4ca..0ceddd0b9ab 100644
> --- a/source3/libsmb/cli_smb2_fnum.h
> +++ b/source3/libsmb/cli_smb2_fnum.h
> @@ -250,4 +250,13 @@ struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
>   DATA_BLOB in_buf);
>  NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req);
>  
> +struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
> + TALLOC_CTX *mem_ctx,
> + struct tevent_context *ev,
> + struct cli_state *cli,
> + uint16_t fnum);
> +NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
> + TALLOC_CTX *mem_ctx,
> + DATA_BLOB *output);
> +
>  #endif /* __SMB2CLI_FNUM_H__ */
> --
> 2.15.0.531.g2ccb3012c9-goog
>
>
> From 5e891a142f85383af68d449671d2fc124bc7a37a Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Wed, 29 Nov 2017 12:38:08 -0800
> Subject: [PATCH 7/7] s3: libsmb: Plumb in the new SMB2 get reparse point calls
>  into the cli_readlink_XXXX() calls.
>
> Reparse point symlinks can now be queried over SMB1 and SMB2 from smbclient.
>
> BUG: https://bugzilla.samba.org/show_bug.cgi?id=13159
>
> Signed-off-by: Jeremy Allison <[hidden email]>
> ---
>  source3/libsmb/clisymlink.c | 41 +++++++++++++++++++++++++++++++----------
>  1 file changed, 31 insertions(+), 10 deletions(-)
>
> diff --git a/source3/libsmb/clisymlink.c b/source3/libsmb/clisymlink.c
> index 202435722c9..54435e468cd 100644
> --- a/source3/libsmb/clisymlink.c
> +++ b/source3/libsmb/clisymlink.c
> @@ -296,17 +296,26 @@ static void cli_readlink_opened(struct tevent_req *subreq)
>   return;
>   }
>  
> - SIVAL(state->setup, 0, FSCTL_GET_REPARSE_POINT);
> - SSVAL(state->setup, 4, state->fnum);
> - SCVAL(state->setup, 6, 1); /* IsFcntl */
> - SCVAL(state->setup, 7, 0); /* IsFlags */
> + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
> + subreq = cli_smb2_get_reparse_point_fnum_send(state,
> + state->ev,
> + state->cli,
> + state->fnum);
> + } else {
> + SIVAL(state->setup, 0, FSCTL_GET_REPARSE_POINT);
> + SSVAL(state->setup, 4, state->fnum);
> + SCVAL(state->setup, 6, 1); /* IsFcntl */
> + SCVAL(state->setup, 7, 0); /* IsFlags */
>  
> - subreq = cli_trans_send(state, state->ev, state->cli, 0, SMBnttrans,
> + subreq = cli_trans_send(state, state->ev, state->cli,
> + 0, SMBnttrans,
>   NULL, -1, /* name, fid */
>   NT_TRANSACT_IOCTL, 0,
>   state->setup, 4, 0, /* setup */
>   NULL, 0, 0,    /* param */
>   NULL, 0, 16384); /* data */
> + }
> +
>   if (tevent_req_nomem(subreq, req)) {
>   return;
>   }
> @@ -320,11 +329,23 @@ static void cli_readlink_got_reparse_data(struct tevent_req *subreq)
>   struct cli_readlink_state *state = tevent_req_data(
>   req, struct cli_readlink_state);
>  
> - state->get_reparse_status = cli_trans_recv(
> - subreq, state, NULL,
> - NULL, 0, NULL, /* rsetup */
> - NULL, 0, NULL, /* rparam */
> - &state->data, 20, &state->num_data); /* rdata */
> + if (smbXcli_conn_protocol(state->cli->conn) >= PROTOCOL_SMB2_02) {
> + DATA_BLOB recv_data;
> + state->get_reparse_status =
> + cli_smb2_get_reparse_point_fnum_recv(subreq,
> + state,
> + &recv_data);
> + if (NT_STATUS_IS_OK(state->get_reparse_status)) {
> + state->data = recv_data.data;
> + state->num_data = recv_data.length;
> + }
> + } else {
> + state->get_reparse_status = cli_trans_recv(
> + subreq, state, NULL,
> + NULL, 0, NULL, /* rsetup */
> + NULL, 0, NULL, /* rparam */
> + &state->data, 20, &state->num_data); /* rdata */
> + }
>   TALLOC_FREE(subreq);
>  
>   subreq = cli_close_send(state, state->ev, state->cli, state->fnum);
> --
> 2.15.0.531.g2ccb3012c9-goog
>


Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient.

Samba - samba-technical mailing list
On Tue, Dec 05, 2017 at 09:41:32AM -0800, Jeremy Allison wrote:
> Ralph, ping ! Can you take a look please ? I'd like this
> in place so I can start on my smbtorture Windows reparse
> points full tests.

sorry. I'll take a look...

-slow

--
Ralph Boehme, Samba Team       https://samba.org/
Samba Developer, SerNet GmbH   https://sernet.de/en/samba/

Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient.

Samba - samba-technical mailing list
In reply to this post by Samba - samba-technical mailing list
Hi Jeremy,

On Thu, Nov 30, 2017 at 04:29:42PM -0800, Jeremy Allison wrote:
> I've tested here and it works. Volker or Ralph, please
> review and push if happy !

few nitpicks below:

> From f082659a2b9a58c2ccef4a1cacc9efa9fd870c7b Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Wed, 22 Nov 2017 00:47:48 +0000
> Subject: [PATCH 1/7] s3: libsmb: Rename cli_close_create() ->
>  cli_smb1_close_create().

patch1: +1

> From 8d5774eb888aee08f4ed2c3a13771b9dc86473b1 Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Mon, 27 Nov 2017 14:38:49 -0800
> Subject: [PATCH 2/7] s3: libsmb: Make cli_close_send()/cli_close_recv() work
>  for SMB1 and SMB2.
>
> Remove the escape into synchronous smb2 code.
>
> BUG: https://bugzilla.samba.org/show_bug.cgi?id=13159
>
> Signed-off-by: Jeremy Allison <[hidden email]>
> ---
>  source3/libsmb/clifile.c | 51 ++++++++++++++++++++++++++++++++++++++++--------
>  1 file changed, 43 insertions(+), 8 deletions(-)
>
> diff --git a/source3/libsmb/clifile.c b/source3/libsmb/clifile.c
> index 2e3c2426030..b0a2759ecf8 100644
> --- a/source3/libsmb/clifile.c
> +++ b/source3/libsmb/clifile.c
> @@ -2818,26 +2818,65 @@ static void cli_smb1_close_done(struct tevent_req *subreq)
>   tevent_req_done(req);
>  }
>  
> +struct cli_close_state {
> + int dummy;
> +};
> +
> +static void cli_close_done(struct tevent_req *subreq);
> +
>  struct tevent_req *cli_close_send(TALLOC_CTX *mem_ctx,
>   struct tevent_context *ev,
>   struct cli_state *cli,
>   uint16_t fnum)
>  {
>   struct tevent_req *req, *subreq;
> + struct cli_close_state *state;
>   NTSTATUS status;
>  
> - req = cli_smb1_close_create(mem_ctx, ev, cli, fnum, &subreq);
> + req = tevent_req_create(mem_ctx, &state, struct cli_close_state);
>   if (req == NULL) {
>   return NULL;
>   }
>  
> - status = smb1cli_req_chain_submit(&subreq, 1);
> - if (tevent_req_nterror(req, status)) {
> - return tevent_req_post(req, ev);
> + if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
> + subreq = cli_smb2_close_fnum_send(mem_ctx,

wrong talloc context for the subreq, should be state.

> + ev,
> + cli,
> + fnum);
> + if (tevent_req_nomem(subreq, req)) {
> + return tevent_req_post(req, ev);
> + }
> + } else {
> + struct tevent_req *ch_req = NULL;
> + subreq = cli_smb1_close_create(mem_ctx, ev, cli, fnum, &ch_req);

dito

> + if (tevent_req_nomem(subreq, req)) {
> + return tevent_req_post(req, ev);
> + }
> + status = smb1cli_req_chain_submit(&ch_req, 1);
> + if (tevent_req_nterror(req, status)) {
> + return tevent_req_post(req, ev);
> + }
>   }
> +
> + tevent_req_set_callback(subreq, cli_close_done, req);
>   return req;
>  }
>  
> +static void cli_close_done(struct tevent_req *subreq)
> +{
> + struct tevent_req *req = tevent_req_callback_data(
> + subreq, struct tevent_req);
> + NTSTATUS status = NT_STATUS_OK;
> + bool err = tevent_req_is_nterror(subreq, &status);
> +
> + TALLOC_FREE(subreq);
> + if (err) {
> + tevent_req_nterror(req, status);
> + return;
> + }
> + tevent_req_done(req);
> +}
> +
>  NTSTATUS cli_close_recv(struct tevent_req *req)
>  {
>   return tevent_req_simple_recv_ntstatus(req);
> @@ -2850,10 +2889,6 @@ NTSTATUS cli_close(struct cli_state *cli, uint16_t fnum)
>   struct tevent_req *req;
>   NTSTATUS status = NT_STATUS_OK;
>  
> - if (smbXcli_conn_protocol(cli->conn) >= PROTOCOL_SMB2_02) {
> - return cli_smb2_close_fnum(cli, fnum);
> - }
> -
>   frame = talloc_stackframe();
>  
>   if (smbXcli_conn_has_async_calls(cli->conn)) {
> --
> 2.15.0.531.g2ccb3012c9-goog
>
>

> From faf81a560bcbaeab3ae0f32f5446716ec10179f1 Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Tue, 28 Nov 2017 14:09:39 -0800
> Subject: [PATCH 3/7] s3: libsmb: Add SMB2 calls
>  cli_smb2_set_reparse_point_fnum_send()/cli_smb2_set_reparse_point_fnum_recv().

patch3: +1

> From 8bae632bf7bd53f1858fe206abf21290fa901367 Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Tue, 28 Nov 2017 14:10:26 -0800
> Subject: [PATCH 4/7] s3: libsmb: Plumb in the new SMB2 reparse point calls
>  into the cli_symlink_create_XXX() calls.

patch4: +1

> From 5eadea9e7cc14ab3d9ebac268ad27b4b089bceef Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Tue, 28 Nov 2017 15:46:40 -0800
> Subject: [PATCH 5/7] s3: libsmb: Do a naive response to SMB2 "stopped on
>  symlink". Assume the last component was the reparse point.

patch5: +1

> From 328229e2fe6a344f895baa47147c1f1aa5c1e2d4 Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Wed, 29 Nov 2017 12:37:36 -0800
> Subject: [PATCH 6/7] s3: libsmb: Add SMB2 calls
>  cli_smb2_get_reparse_point_fnum_send()/cli_smb2_get_reparse_point_fnum_recv().
>
> Allow reparse points to be queried over SMB2.
>
> BUG: https://bugzilla.samba.org/show_bug.cgi?id=13159
>
> Signed-off-by: Jeremy Allison <[hidden email]>
> ---
>  source3/libsmb/cli_smb2_fnum.c | 96 ++++++++++++++++++++++++++++++++++++++++++
>  source3/libsmb/cli_smb2_fnum.h |  9 ++++
>  2 files changed, 105 insertions(+)
>
> diff --git a/source3/libsmb/cli_smb2_fnum.c b/source3/libsmb/cli_smb2_fnum.c
> index c40d6dd3a45..a54c248720b 100644
> --- a/source3/libsmb/cli_smb2_fnum.c
> +++ b/source3/libsmb/cli_smb2_fnum.c
> @@ -4337,3 +4337,99 @@ NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req)
>  {
>          return tevent_req_simple_recv_ntstatus(req);
>  }
> +
> +struct cli_smb2_get_reparse_point_fnum_state {
> + struct cli_state *cli;
> + uint16_t fnum;
> + struct smb2_hnd *ph;
> + DATA_BLOB output_buffer;
> +};
> +
> +static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq);
> +
> +struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
> + TALLOC_CTX *mem_ctx,
> + struct tevent_context *ev,
> + struct cli_state *cli,
> + uint16_t fnum)
> +{
> + struct tevent_req *req, *subreq;
> + struct cli_smb2_set_reparse_point_fnum_state *state = NULL;
> + NTSTATUS status;
> +
> + req = tevent_req_create(mem_ctx, &state,
> + struct cli_smb2_get_reparse_point_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);
> + }
> +
> + 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_REPARSE_POINT,
> + 0, /* in_max_input_length */
> + NULL,
> + 64*1024,
> + NULL,
> + SMB2_IOCTL_FLAG_IS_FSCTL);
> +
> + if (tevent_req_nomem(subreq, req)) {
> + return tevent_req_post(req, ev);
> + }
> + tevent_req_set_callback(subreq,
> + cli_smb2_get_reparse_point_fnum_done,
> + req);
> +
> + return req;
> +}
> +
> +static void cli_smb2_get_reparse_point_fnum_done(struct tevent_req *subreq)
> +{
> + struct tevent_req *req = tevent_req_callback_data(
> + subreq, struct tevent_req);
> + struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
> + req, struct cli_smb2_get_reparse_point_fnum_state);
> + NTSTATUS status;
> +
> + status = smb2cli_ioctl_recv(subreq, state,
> + NULL,
> + &state->output_buffer);
> + TALLOC_FREE(subreq);
> + if (tevent_req_nterror(req, status)) {
> + return;
> + }
> + tevent_req_done(req);
> +}
> +
> +NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
> + TALLOC_CTX *mem_ctx,
> + DATA_BLOB *output)
> +{
> + struct cli_smb2_get_reparse_point_fnum_state *state = tevent_req_data(
> + req, struct cli_smb2_get_reparse_point_fnum_state);
> +
> + if (tevent_req_is_nterror(req, &state->cli->raw_status)) {
> + return state->cli->raw_status;
> + }
> + *output = data_blob_dup_talloc(mem_ctx, state->output_buffer);

missing tevent_req_received().

> + if (output->data == NULL) {
> + return NT_STATUS_NO_MEMORY;
> + }
> + return NT_STATUS_OK;
> +}
> diff --git a/source3/libsmb/cli_smb2_fnum.h b/source3/libsmb/cli_smb2_fnum.h
> index 0f6809fe4ca..0ceddd0b9ab 100644
> --- a/source3/libsmb/cli_smb2_fnum.h
> +++ b/source3/libsmb/cli_smb2_fnum.h
> @@ -250,4 +250,13 @@ struct tevent_req *cli_smb2_set_reparse_point_fnum_send(
>   DATA_BLOB in_buf);
>  NTSTATUS cli_smb2_set_reparse_point_fnum_recv(struct tevent_req *req);
>  
> +struct tevent_req *cli_smb2_get_reparse_point_fnum_send(
> + TALLOC_CTX *mem_ctx,
> + struct tevent_context *ev,
> + struct cli_state *cli,
> + uint16_t fnum);
> +NTSTATUS cli_smb2_get_reparse_point_fnum_recv(struct tevent_req *req,
> + TALLOC_CTX *mem_ctx,
> + DATA_BLOB *output);
> +
>  #endif /* __SMB2CLI_FNUM_H__ */
> --
> 2.15.0.531.g2ccb3012c9-goog
>
>
> From 5e891a142f85383af68d449671d2fc124bc7a37a Mon Sep 17 00:00:00 2001
> From: Jeremy Allison <[hidden email]>
> Date: Wed, 29 Nov 2017 12:38:08 -0800
> Subject: [PATCH 7/7] s3: libsmb: Plumb in the new SMB2 get reparse point calls
>  into the cli_readlink_XXXX() calls.

patch7: +1

-slow

--
Ralph Boehme, Samba Team       https://samba.org/
Samba Developer, SerNet GmbH   https://sernet.de/en/samba/

Reply | Threaded
Open this post in threaded view
|

[PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient - version #2

Samba - samba-technical mailing list
On Tue, Dec 05, 2017 at 11:26:21PM +0100, Ralph Böhme wrote:
> Hi Jeremy,
>
> On Thu, Nov 30, 2017 at 04:29:42PM -0800, Jeremy Allison wrote:
> > I've tested here and it works. Volker or Ralph, please
> > review and push if happy !
>
> few nitpicks below:

Updated version that should fix the issues you
mentioned. Thanks a *LOT* for the careful review !

Jeremy.

bug-13159-master-p2 (27K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: [PATCH] Allow reparse points to be created/read/removed over SMB2 from smbclient - version #2

Samba - samba-technical mailing list
On Tue, Dec 05, 2017 at 03:56:04PM -0800, Jeremy Allison wrote:

> On Tue, Dec 05, 2017 at 11:26:21PM +0100, Ralph Böhme wrote:
> > Hi Jeremy,
> >
> > On Thu, Nov 30, 2017 at 04:29:42PM -0800, Jeremy Allison wrote:
> > > I've tested here and it works. Volker or Ralph, please
> > > review and push if happy !
> >
> > few nitpicks below:
>
> Updated version that should fix the issues you
> mentioned. Thanks a *LOT* for the careful review !

pushed after inserting two more tevent_req_received() in error code paths.

Thanks!
-slow

--
Ralph Boehme, Samba Team       https://samba.org/
Samba Developer, SerNet GmbH   https://sernet.de/en/samba/