The Samba-Bugzilla – Attachment 17473 Details for
Bug 15144
4.17.rc1 still uses symlink-race prone unix_convert()
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
Help
|
New Account
|
Log In
[x]
|
Forgot Password
Login:
[x]
[patch]
git-am fix for 4.17.rc2
bug-15144-4.17 (text/plain), 112.90 KB, created by
Jeremy Allison
on 2022-08-12 19:34:03 UTC
(
hide
)
Description:
git-am fix for 4.17.rc2
Filename:
MIME Type:
Creator:
Jeremy Allison
Created:
2022-08-12 19:34:03 UTC
Size:
112.90 KB
patch
obsolete
>From 12ab932affea36c8ef305e8c22cd7bc0d3f09f46 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 5 Aug 2022 19:27:33 -0700 >Subject: [PATCH 01/25] s3: smbd: Fix cosmetic bug logging pathnames from Linux > kernel clients using SMB1 DFS calls. > >The Linux kernel SMB1 client has a bug - it sends >DFS pathnames as: > >\\server\share\path > >instead of: > >\server\share\path > >Causing us to mis-parse server,share,remaining_path here >and jump into 'goto local_path' at 'share\path' instead >of 'path'. > >This doesn't cause an error as the limits on share names >are similar to those on pathnames. > >parse_dfs_path() which we call before filename parsing >copes with this by calling trim_char on the leading '\' >characters before processing. > >Do the same here so logging of pathnames looks better. > >How did I find this ? Lots and lots of manual >testing with the Linux kernel client to make >sure all the recent changes haven't broken Linux >SMB1/2/3 DFS :-). > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit 2818fd6910201fd4a18b921933a0b7392a0a8995) >--- > source3/smbd/smb2_reply.c | 23 +++++++++++++++++++++++ > 1 file changed, 23 insertions(+) > >diff --git a/source3/smbd/smb2_reply.c b/source3/smbd/smb2_reply.c >index 42601879c09..870c3bcb898 100644 >--- a/source3/smbd/smb2_reply.c >+++ b/source3/smbd/smb2_reply.c >@@ -310,6 +310,29 @@ static size_t srvstr_get_path_internal(TALLOC_CTX *ctx, > */ > server = dst; > >+ /* >+ * Cosmetic fix for Linux-only DFS clients. >+ * The Linux kernel SMB1 client has a bug - it sends >+ * DFS pathnames as: >+ * >+ * \\server\share\path >+ * >+ * Causing us to mis-parse server,share,remaining_path here >+ * and jump into 'goto local_path' at 'share\path' instead >+ * of 'path'. >+ * >+ * This doesn't cause an error as the limits on share names >+ * are similar to those on pathnames. >+ * >+ * parse_dfs_path() which we call before filename parsing >+ * copes with this by calling trim_char on the leading '\' >+ * characters before processing. >+ * Do the same here so logging of pathnames looks better. >+ */ >+ if (server[1] == path_sep) { >+ trim_char(&server[1], path_sep, '\0'); >+ } >+ > /* > * Look to see if we also have /share following. > */ >-- >2.34.1 > > >From 5a49e2eafde4d377adf1a1d14e7911389390c843 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Fri, 5 Aug 2022 12:16:44 -0700 >Subject: [PATCH 02/25] s3: smbd: Add new function > check_path_syntax_smb2_msdfs() for SMB2 MSDFS paths. > > #ifdef'ed out as static and not yet used. > >We can't just call check_path_syntax() on these as >they are of the form hostname\share[\extrapath] >(where [\extrapath] is optional). > >hostname here can be an IPv6 ':' separated address, >which check_path_syntax() fails on due to the streamname >processing. > >NB. This also has to cope with out existing (broken) >libsmbclient libraries that sometimes set the DFS >flag and then send a local pathname. Cope by just >calling the normal check_path_syntax() on the >whole pathname in that case. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit bcba5502282eb6dcc346d7c63aa3218cda2f9bb0) >--- > source3/smbd/smb2_reply.c | 38 ++++++++++++++++++++++++++++++++++++++ > 1 file changed, 38 insertions(+) > >diff --git a/source3/smbd/smb2_reply.c b/source3/smbd/smb2_reply.c >index 870c3bcb898..6052f94354a 100644 >--- a/source3/smbd/smb2_reply.c >+++ b/source3/smbd/smb2_reply.c >@@ -243,6 +243,44 @@ NTSTATUS check_path_syntax_posix(char *path) > return check_path_syntax_internal(path, true); > } > >+#if 0 >+/**************************************************************************** >+ Check the path for an SMB2 DFS path. >+ SMB2 DFS paths look like hostname\share (followed by a possible \extrapath. >+ Path returned from here must look like: >+ hostname/share (followed by a possible /extrapath). >+****************************************************************************/ >+ >+static NTSTATUS check_path_syntax_smb2_msdfs(char *path) >+{ >+ char *share = NULL; >+ char *remaining_path = NULL; >+ /* No SMB2 names can start with '\\' */ >+ if (path[0] == '\\') { >+ return NT_STATUS_OBJECT_NAME_INVALID; >+ } >+ /* >+ * smbclient libraries sometimes set the DFS flag and send >+ * local pathnames. Cope with this by just calling >+ * check_path_syntax() on the whole path if it doesn't >+ * look like a DFS path, similar to what parse_dfs_path() does. >+ */ >+ /* servername should be at path[0] */ >+ share = strchr(path, '\\'); >+ if (share == NULL) { >+ return check_path_syntax(path); >+ } >+ *share++ = '/'; >+ remaining_path = strchr(share, '\\'); >+ if (remaining_path == NULL) { >+ /* Only hostname\share. We're done. */ >+ return NT_STATUS_OK; >+ } >+ *remaining_path++ = '/'; >+ return check_path_syntax(remaining_path); >+} >+#endif >+ > /**************************************************************************** > Pull a string and check the path allowing a wildcard - provide for error return. > Passes in posix flag. >-- >2.34.1 > > >From de02e12e578eec361c468e4f0ff041ce176b60b4 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 9 Aug 2022 10:36:00 -0700 >Subject: [PATCH 03/25] s3: smbd: Add helper function check_path_syntax_smb2(). > >Not yet used, but uses check_path_syntax_smb2_msdfs() >so remove the #ifdef's around that. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit 7bd7fa0a0b46ad6826097a1987595e2ab6f83384) >--- > source3/smbd/proto.h | 1 + > source3/smbd/smb2_reply.c | 11 +++++++++-- > 2 files changed, 10 insertions(+), 2 deletions(-) > >diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h >index ceee52d79cd..33fc222311e 100644 >--- a/source3/smbd/proto.h >+++ b/source3/smbd/proto.h >@@ -941,6 +941,7 @@ bool disk_quotas(connection_struct *conn, struct smb_filename *fname, > > NTSTATUS check_path_syntax(char *path); > NTSTATUS check_path_syntax_posix(char *path); >+NTSTATUS check_path_syntax_smb2(char *path, bool dfs_path); > size_t srvstr_get_path(TALLOC_CTX *ctx, > const char *inbuf, > uint16_t smb_flags2, >diff --git a/source3/smbd/smb2_reply.c b/source3/smbd/smb2_reply.c >index 6052f94354a..0303db428f2 100644 >--- a/source3/smbd/smb2_reply.c >+++ b/source3/smbd/smb2_reply.c >@@ -243,7 +243,6 @@ NTSTATUS check_path_syntax_posix(char *path) > return check_path_syntax_internal(path, true); > } > >-#if 0 > /**************************************************************************** > Check the path for an SMB2 DFS path. > SMB2 DFS paths look like hostname\share (followed by a possible \extrapath. >@@ -279,7 +278,15 @@ static NTSTATUS check_path_syntax_smb2_msdfs(char *path) > *remaining_path++ = '/'; > return check_path_syntax(remaining_path); > } >-#endif >+ >+NTSTATUS check_path_syntax_smb2(char *path, bool dfs_path) >+{ >+ if (dfs_path) { >+ return check_path_syntax_smb2_msdfs(path); >+ } else { >+ return check_path_syntax(path); >+ } >+} > > /**************************************************************************** > Pull a string and check the path allowing a wildcard - provide for error return. >-- >2.34.1 > > >From ba056f7f7b00befb945df9f048139f78b49a0281 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 9 Aug 2022 10:39:41 -0700 >Subject: [PATCH 04/25] s3: smbd: In smbd_smb2_create_send() call the helper > function check_path_syntax_smb2(). > >Previously for DFS names we were skipping this. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit 4fafc3418931de06ea2d91baca1eef8d904cc4e6) >--- > source3/smbd/smb2_create.c | 18 +++++++----------- > 1 file changed, 7 insertions(+), 11 deletions(-) > >diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c >index dbafaf01597..8ef605dea66 100644 >--- a/source3/smbd/smb2_create.c >+++ b/source3/smbd/smb2_create.c >@@ -714,6 +714,7 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, > struct files_struct *dirfsp = NULL; > struct smb_filename *smb_fname = NULL; > uint32_t ucf_flags; >+ bool is_dfs = false; > > req = tevent_req_create(mem_ctx, &state, > struct smbd_smb2_create_state); >@@ -959,18 +960,13 @@ static struct tevent_req *smbd_smb2_create_send(TALLOC_CTX *mem_ctx, > state->lease_ptr = NULL; > } > >- /* >- * For a DFS path the function parse_dfs_path() >- * will do the path processing. >- */ >+ is_dfs = (smb1req->flags2 & FLAGS2_DFS_PATHNAMES); > >- if (!(smb1req->flags2 & FLAGS2_DFS_PATHNAMES)) { >- /* convert '\\' into '/' */ >- status = check_path_syntax(state->fname); >- if (!NT_STATUS_IS_OK(status)) { >- tevent_req_nterror(req, status); >- return tevent_req_post(req, state->ev); >- } >+ /* convert '\\' into '/' */ >+ status = check_path_syntax_smb2(state->fname, is_dfs); >+ if (!NT_STATUS_IS_OK(status)) { >+ tevent_req_nterror(req, status); >+ return tevent_req_post(req, state->ev); > } > > ucf_flags = filename_create_ucf_flags( >-- >2.34.1 > > >From 5dcf3dfd09eb75496205acac3538836d5ebb27e2 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 9 Aug 2022 10:41:39 -0700 >Subject: [PATCH 05/25] s3: smbd: Make sure we have identical check_path_syntax > logic in smbd_smb2_create_durable_lease_check(), as for smb2_create. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit a2a097fc3d6a89fb970c1ea3ea75fde93ddb545e) >--- > source3/smbd/smb2_create.c | 3 ++- > 1 file changed, 2 insertions(+), 1 deletion(-) > >diff --git a/source3/smbd/smb2_create.c b/source3/smbd/smb2_create.c >index 8ef605dea66..75b9c7d28ff 100644 >--- a/source3/smbd/smb2_create.c >+++ b/source3/smbd/smb2_create.c >@@ -430,6 +430,7 @@ static NTSTATUS smbd_smb2_create_durable_lease_check(struct smb_request *smb1req > uint32_t ucf_flags; > NTTIME twrp = fsp->fsp_name->twrp; > NTSTATUS status; >+ bool is_dfs = (smb1req->flags2 & FLAGS2_DFS_PATHNAMES); > > if (lease_ptr == NULL) { > if (fsp->oplock_type != LEASE_OPLOCK) { >@@ -459,7 +460,7 @@ static NTSTATUS smbd_smb2_create_durable_lease_check(struct smb_request *smb1req > } > > /* This also converts '\' to '/' */ >- status = check_path_syntax(filename); >+ status = check_path_syntax_smb2(filename, is_dfs); > if (!NT_STATUS_IS_OK(status)) { > TALLOC_FREE(filename); > return status; >-- >2.34.1 > > >From 5155d323497d8f9529d5fc7b9a0b14c175cb7ab1 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 9 Aug 2022 10:43:45 -0700 >Subject: [PATCH 06/25] s3: smbd: Ensure smb2_file_rename_information() uses > the SMB2 pathname parsers, not the SMB1 parsers. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit 0a4a27ce48bc7090aa821eea5e56f8d44c686716) >--- > source3/smbd/smb2_trans2.c | 30 ++++++++++++------------------ > 1 file changed, 12 insertions(+), 18 deletions(-) > >diff --git a/source3/smbd/smb2_trans2.c b/source3/smbd/smb2_trans2.c >index d0f30a782bf..b2a0cc4140a 100644 >--- a/source3/smbd/smb2_trans2.c >+++ b/source3/smbd/smb2_trans2.c >@@ -4957,6 +4957,7 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn, > uint32_t ucf_flags = ucf_flags_from_smb_request(req); > NTTIME dst_twrp = 0; > NTSTATUS status = NT_STATUS_OK; >+ bool is_dfs = (req->flags2 & FLAGS2_DFS_PATHNAMES); > TALLOC_CTX *ctx = talloc_tos(); > > if (!fsp) { >@@ -4974,25 +4975,18 @@ static NTSTATUS smb2_file_rename_information(connection_struct *conn, > return NT_STATUS_INVALID_PARAMETER; > } > >- if (req->posix_pathnames) { >- srvstr_get_path_posix(ctx, >- pdata, >- req->flags2, >- &newname, >- &pdata[20], >- len, >- STR_TERMINATE, >- &status); >- } else { >- srvstr_get_path(ctx, >- pdata, >- req->flags2, >- &newname, >- &pdata[20], >- len, >- STR_TERMINATE, >- &status); >+ (void)srvstr_pull_talloc(ctx, >+ pdata, >+ req->flags2, >+ &newname, >+ &pdata[20], >+ len, >+ STR_TERMINATE); >+ >+ if (newname == NULL) { >+ return NT_STATUS_INVALID_PARAMETER; > } >+ status = check_path_syntax_smb2(newname, is_dfs); > if (!NT_STATUS_IS_OK(status)) { > return status; > } >-- >2.34.1 > > >From 8c47743593d0b9792db4f864ee976f613047a10e Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Wed, 10 Aug 2022 11:06:47 -0700 >Subject: [PATCH 07/25] s3: smbd: Add TALLOC_CTX * parameter to > parse_dfs_path(). > >Not yet used. Preparing to remove 'struct dfs_path'. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit 2df8a8ab87a1372f2b67880be4454a0285b3104b) >--- > source3/smbd/msdfs.c | 22 +++++++++++++++++----- > 1 file changed, 17 insertions(+), 5 deletions(-) > >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index a52a2449965..abe447dd056 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -58,7 +58,8 @@ > JRA. > **********************************************************************/ > >-static NTSTATUS parse_dfs_path(connection_struct *conn, >+static NTSTATUS parse_dfs_path(TALLOC_CTX *ctx, >+ connection_struct *conn, > const char *pathname, > bool allow_broken_path, > struct dfs_path *pdp) /* MUST BE TALLOCED */ >@@ -870,8 +871,11 @@ NTSTATUS dfs_redirect(TALLOC_CTX *ctx, > return NT_STATUS_NO_MEMORY; > } > >- status = parse_dfs_path(conn, path_in, >- allow_broken_path, pdp); >+ status = parse_dfs_path(ctx, >+ conn, >+ path_in, >+ allow_broken_path, >+ pdp); > if (!NT_STATUS_IS_OK(status)) { > TALLOC_FREE(pdp); > return status; >@@ -1020,7 +1024,11 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, > > *self_referralp = False; > >- status = parse_dfs_path(NULL, dfs_path, allow_broken_path, pdp); >+ status = parse_dfs_path(frame, >+ NULL, >+ dfs_path, >+ allow_broken_path, >+ pdp); > if (!NT_STATUS_IS_OK(status)) { > TALLOC_FREE(frame); > return status; >@@ -1269,7 +1277,11 @@ bool create_junction(TALLOC_CTX *ctx, > if (!pdp) { > return False; > } >- status = parse_dfs_path(NULL, dfs_path, allow_broken_path, pdp); >+ status = parse_dfs_path(ctx, >+ NULL, >+ dfs_path, >+ allow_broken_path, >+ pdp); > if (!NT_STATUS_IS_OK(status)) { > return False; > } >-- >2.34.1 > > >From 4073edd33916d2c29431cad5fb1e0550782a704a Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Wed, 10 Aug 2022 11:17:49 -0700 >Subject: [PATCH 08/25] s3: smbd: Remove use of 'struct dfs_path'. Not needed > for a (hostname, servicename, path) tuple. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit f92711f000a3cb658dfb8fffe92ae6bba78b4f91) >--- > source3/smbd/msdfs.c | 167 ++++++++++++++++++++++--------------------- > 1 file changed, 87 insertions(+), 80 deletions(-) > >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index abe447dd056..21288aaf664 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -62,24 +62,20 @@ static NTSTATUS parse_dfs_path(TALLOC_CTX *ctx, > connection_struct *conn, > const char *pathname, > bool allow_broken_path, >- struct dfs_path *pdp) /* MUST BE TALLOCED */ >+ char **_hostname, >+ char **_servicename, >+ char **_remaining_path) > { > const struct loadparm_substitution *lp_sub = > loadparm_s3_global_substitution(); >- char *pathname_local; >- char *p; >- char *servicename; >- char *eos_ptr; >- >- ZERO_STRUCTP(pdp); >- >- /* >- * This is the only talloc we should need to do >- * on the struct dfs_path. All the pointers inside >- * it should point to offsets within this string. >- */ >+ char *hostname = NULL; >+ char *pathname_local = NULL; >+ char *p = NULL; >+ char *servicename = NULL; >+ char *reqpath = NULL; >+ char *eos_ptr = NULL; > >- pathname_local = talloc_strdup(pdp, pathname); >+ pathname_local = talloc_strdup(ctx, pathname); > if (pathname_local == NULL) { > return NT_STATUS_NO_MEMORY; > } >@@ -109,8 +105,8 @@ static NTSTATUS parse_dfs_path(TALLOC_CTX *ctx, > * to cope with known broken SMB1 clients. > */ > >- pdp->hostname = eos_ptr; /* "" */ >- pdp->servicename = eos_ptr; /* "" */ >+ hostname = eos_ptr; /* "" */ >+ servicename = eos_ptr; /* "" */ > > DBG_ERR("trying to convert %s to a local path\n", p); > goto local_path; >@@ -134,17 +130,17 @@ static NTSTATUS parse_dfs_path(TALLOC_CTX *ctx, > * Try and convert to a local path. > */ > >- pdp->hostname = eos_ptr; /* "" */ >- pdp->servicename = eos_ptr; /* "" */ >+ hostname = eos_ptr; /* "" */ >+ servicename = eos_ptr; /* "" */ > > p = pathname_local; > DBG_ERR("trying to convert %s to a local path\n", p); > goto local_path; > } > *p = '\0'; >- pdp->hostname = pathname_local; >+ hostname = pathname_local; > >- DBG_DEBUG("hostname: %s\n",pdp->hostname); >+ DBG_DEBUG("hostname: %s\n", hostname); > > /* Parse out servicename. */ > servicename = p+1; >@@ -165,9 +161,6 @@ static NTSTATUS parse_dfs_path(TALLOC_CTX *ctx, > * Try and convert to a local path. > */ > >- pdp->hostname = eos_ptr; /* "" */ >- pdp->servicename = eos_ptr; /* "" */ >- > /* Repair the path - replace the sepchar's > we nulled out */ > servicename--; >@@ -176,20 +169,23 @@ static NTSTATUS parse_dfs_path(TALLOC_CTX *ctx, > *p = '/'; > } > >+ hostname = eos_ptr; /* "" */ >+ servicename = eos_ptr; /* "" */ >+ > p = pathname_local; > DBG_ERR("trying to convert %s to a local path\n", > pathname_local); > goto local_path; > } > >- pdp->servicename = servicename; >+ servicename = servicename; > >- DBG_DEBUG("servicename: %s\n", pdp->servicename); >+ DBG_DEBUG("servicename: %s\n", servicename); > > if(p == NULL) { > /* Client sent self referral \server\share. */ >- pdp->reqpath = eos_ptr; /* "" */ >- return NT_STATUS_OK; >+ reqpath = eos_ptr; /* "" */ >+ goto out; > } > > p++; >@@ -202,8 +198,31 @@ static NTSTATUS parse_dfs_path(TALLOC_CTX *ctx, > * '/' separators. > */ > >- pdp->reqpath = p; >- DBG_DEBUG("rest of the path: %s\n", pdp->reqpath); >+ reqpath = p; >+ >+ out: >+ >+ DBG_DEBUG("rest of the path: %s\n", reqpath); >+ >+ if (_hostname != NULL) { >+ *_hostname = talloc_strdup(ctx, hostname); >+ if (*_hostname == NULL) { >+ return NT_STATUS_NO_MEMORY; >+ } >+ } >+ if (_servicename != NULL) { >+ *_servicename = talloc_strdup(ctx, servicename); >+ if (*_servicename == NULL) { >+ return NT_STATUS_NO_MEMORY; >+ } >+ } >+ if (_remaining_path != NULL) { >+ *_remaining_path = talloc_strdup(ctx, reqpath); >+ if (*_remaining_path == NULL) { >+ return NT_STATUS_NO_MEMORY; >+ } >+ } >+ TALLOC_FREE(pathname_local); > return NT_STATUS_OK; > } > >@@ -663,8 +682,7 @@ bool is_msdfs_link(struct files_struct *dirfsp, > static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, > connection_struct *conn, > const char *dfspath, /* Incoming complete dfs path */ >- const struct dfs_path *pdp, /* Parsed out >- server+share+extrapath. */ >+ const char *reqpath, /* Parsed out remaining path. */ > uint32_t ucf_flags, > NTTIME *_twrp, > size_t *consumedcntp, >@@ -681,7 +699,7 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, > components). */ > > DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n", >- conn->connectpath, pdp->reqpath)); >+ conn->connectpath, reqpath)); > > /* > * Note the unix path conversion here we're doing we >@@ -690,7 +708,7 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, > * unix_convert later in the codepath. > */ > >- status = unix_convert(ctx, conn, pdp->reqpath, 0, &smb_fname, >+ status = unix_convert(ctx, conn, reqpath, 0, &smb_fname, > ucf_flags); > > if (!NT_STATUS_IS_OK(status)) { >@@ -864,25 +882,23 @@ NTSTATUS dfs_redirect(TALLOC_CTX *ctx, > { > const struct loadparm_substitution *lp_sub = > loadparm_s3_global_substitution(); >+ char *hostname = NULL; >+ char *servicename = NULL; >+ char *reqpath = NULL; > NTSTATUS status; >- struct dfs_path *pdp = talloc(ctx, struct dfs_path); >- >- if (!pdp) { >- return NT_STATUS_NO_MEMORY; >- } > > status = parse_dfs_path(ctx, > conn, > path_in, > allow_broken_path, >- pdp); >+ &hostname, >+ &servicename, >+ &reqpath); > if (!NT_STATUS_IS_OK(status)) { >- TALLOC_FREE(pdp); > return status; > } > >- if (pdp->reqpath[0] == '\0') { >- TALLOC_FREE(pdp); >+ if (reqpath[0] == '\0') { > *pp_path_out = talloc_strdup(ctx, ""); > if (!*pp_path_out) { > return NT_STATUS_NO_MEMORY; >@@ -895,8 +911,7 @@ NTSTATUS dfs_redirect(TALLOC_CTX *ctx, > path and return OK */ > > if (!lp_msdfs_root(SNUM(conn))) { >- *pp_path_out = talloc_strdup(ctx, pdp->reqpath); >- TALLOC_FREE(pdp); >+ *pp_path_out = talloc_strdup(ctx, reqpath); > if (!*pp_path_out) { > return NT_STATUS_NO_MEMORY; > } >@@ -906,30 +921,27 @@ NTSTATUS dfs_redirect(TALLOC_CTX *ctx, > /* If it looked like a local path (zero hostname/servicename) > * just treat as a tcon-relative path. */ > >- if (pdp->hostname[0] == '\0' && pdp->servicename[0] == '\0') { >- *pp_path_out = talloc_strdup(ctx, pdp->reqpath); >- TALLOC_FREE(pdp); >+ if (hostname[0] == '\0' && servicename[0] == '\0') { >+ *pp_path_out = talloc_strdup(ctx, reqpath); > if (!*pp_path_out) { > return NT_STATUS_NO_MEMORY; > } > return NT_STATUS_OK; > } > >- if (!( strequal(pdp->servicename, lp_servicename(talloc_tos(), lp_sub, SNUM(conn))) >- || (strequal(pdp->servicename, HOMES_NAME) >+ if (!( strequal(servicename, lp_servicename(talloc_tos(), lp_sub, SNUM(conn))) >+ || (strequal(servicename, HOMES_NAME) > && strequal(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), > conn->session_info->unix_info->sanitized_username) )) ) { > > /* The given sharename doesn't match this connection. */ >- TALLOC_FREE(pdp); >- > return NT_STATUS_OBJECT_PATH_NOT_FOUND; > } > > status = dfs_path_lookup(ctx, > conn, > path_in, >- pdp, >+ reqpath, > ucf_flags, > _twrp, /* twrp. */ > NULL, /* size_t *consumedcntp */ >@@ -949,8 +961,7 @@ NTSTATUS dfs_redirect(TALLOC_CTX *ctx, > DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in)); > > /* Form non-dfs tcon-relative path */ >- *pp_path_out = talloc_strdup(ctx, pdp->reqpath); >- TALLOC_FREE(pdp); >+ *pp_path_out = talloc_strdup(ctx, reqpath); > if (!*pp_path_out) { > return NT_STATUS_NO_MEMORY; > } >@@ -1013,14 +1024,10 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, > loadparm_s3_global_substitution(); > struct conn_struct_tos *c = NULL; > struct connection_struct *conn = NULL; >+ char *servicename = NULL; >+ char *reqpath = NULL; > int snum; > NTSTATUS status = NT_STATUS_NOT_FOUND; >- struct dfs_path *pdp = talloc_zero(frame, struct dfs_path); >- >- if (!pdp) { >- TALLOC_FREE(frame); >- return NT_STATUS_NO_MEMORY; >- } > > *self_referralp = False; > >@@ -1028,14 +1035,16 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, > NULL, > dfs_path, > allow_broken_path, >- pdp); >+ NULL, >+ &servicename, >+ &reqpath); > if (!NT_STATUS_IS_OK(status)) { > TALLOC_FREE(frame); > return status; > } > >- jucn->service_name = talloc_strdup(ctx, pdp->servicename); >- jucn->volume_name = talloc_strdup(ctx, pdp->reqpath); >+ jucn->service_name = talloc_strdup(ctx, servicename); >+ jucn->volume_name = talloc_strdup(ctx, reqpath); > if (!jucn->service_name || !jucn->volume_name) { > TALLOC_FREE(frame); > return NT_STATUS_NO_MEMORY; >@@ -1064,7 +1073,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, > if (!lp_msdfs_root(snum) && (*lp_msdfs_proxy(talloc_tos(), lp_sub, snum) == '\0')) { > DEBUG(3,("get_referred_path: |%s| in dfs path %s is not " > "a dfs root.\n", >- pdp->servicename, dfs_path)); >+ servicename, dfs_path)); > TALLOC_FREE(frame); > return NT_STATUS_NOT_FOUND; > } >@@ -1077,7 +1086,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, > * user). Cope with this. > */ > >- if (pdp->reqpath[0] == '\0') { >+ if (reqpath[0] == '\0') { > char *tmp; > struct referral *ref; > size_t refcount; >@@ -1158,7 +1167,7 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, > status = dfs_path_lookup(ctx, > conn, > dfs_path, >- pdp, >+ reqpath, > 0, /* ucf_flags */ > NULL, > consumedcntp, >@@ -1271,45 +1280,43 @@ bool create_junction(TALLOC_CTX *ctx, > const struct loadparm_substitution *lp_sub = > loadparm_s3_global_substitution(); > int snum; >- struct dfs_path *pdp = talloc(ctx,struct dfs_path); >+ char *hostname = NULL; >+ char *servicename = NULL; >+ char *reqpath = NULL; > NTSTATUS status; > >- if (!pdp) { >- return False; >- } > status = parse_dfs_path(ctx, > NULL, > dfs_path, > allow_broken_path, >- pdp); >+ &hostname, >+ &servicename, >+ &reqpath); > if (!NT_STATUS_IS_OK(status)) { > return False; > } > > /* check if path is dfs : validate first token */ >- if (!is_myname_or_ipaddr(pdp->hostname)) { >+ if (!is_myname_or_ipaddr(hostname)) { > DEBUG(4,("create_junction: Invalid hostname %s " > "in dfs path %s\n", >- pdp->hostname, dfs_path)); >- TALLOC_FREE(pdp); >+ hostname, dfs_path)); > return False; > } > > /* Check for a non-DFS share */ >- snum = lp_servicenumber(pdp->servicename); >+ snum = lp_servicenumber(servicename); > > if(snum < 0 || !lp_msdfs_root(snum)) { > DEBUG(4,("create_junction: %s is not an msdfs root.\n", >- pdp->servicename)); >- TALLOC_FREE(pdp); >+ servicename)); > return False; > } > >- jucn->service_name = talloc_strdup(ctx, pdp->servicename); >- jucn->volume_name = talloc_strdup(ctx, pdp->reqpath); >+ jucn->service_name = talloc_strdup(ctx, servicename); >+ jucn->volume_name = talloc_strdup(ctx, reqpath); > jucn->comment = lp_comment(ctx, lp_sub, snum); > >- TALLOC_FREE(pdp); > if (!jucn->service_name || !jucn->volume_name || ! jucn->comment) { > return False; > } >-- >2.34.1 > > >From 58844fa8aee5458feeb666a89fad6f98ca110b3b Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 8 Aug 2022 10:27:16 -0700 >Subject: [PATCH 09/25] s3: smbd: Remove definition of struct dfs_path. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit 6c83c674bab8e57ecaf6271eb3a403171bbbacca) >--- > source3/include/msdfs.h | 7 ------- > 1 file changed, 7 deletions(-) > >diff --git a/source3/include/msdfs.h b/source3/include/msdfs.h >index 83265174373..892343fdd9a 100644 >--- a/source3/include/msdfs.h >+++ b/source3/include/msdfs.h >@@ -56,11 +56,4 @@ struct junction_map { > size_t referral_count; > struct referral* referral_list; > }; >- >-struct dfs_path { >- char *hostname; >- char *servicename; >- char *reqpath; >-}; >- > #endif /* _MSDFS_H */ >-- >2.34.1 > > >From 9472c84db87e97b725b72c3d243498e6c4b6c521 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 9 Aug 2022 10:49:46 -0700 >Subject: [PATCH 10/25] s3: smbd: Add helper function > msdfs_servicename_matches_connection(). > >Not yet used so commented out. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit 4f5d02f8c0efc1520b2113ce656c78483deb7826) >--- > source3/smbd/msdfs.c | 46 ++++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 46 insertions(+) > >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index 21288aaf664..463601cf1ee 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -36,6 +36,52 @@ > #include "lib/global_contexts.h" > #include "source3/lib/substitute.h" > >+#if 0 >+/********************************************************************** >+ Function to determine if a given sharename matches a connection. >+**********************************************************************/ >+ >+static bool msdfs_servicename_matches_connection(struct connection_struct *conn, >+ const char *servicename, >+ const char *vfs_user) >+{ >+ const struct loadparm_substitution *lp_sub = >+ loadparm_s3_global_substitution(); >+ char *conn_servicename = NULL; >+ int snum; >+ bool match = false; >+ >+ if (conn == NULL) { >+ /* No connection always matches. */ >+ return true; >+ } >+ >+ snum = SNUM(conn); >+ >+ conn_servicename = lp_servicename(talloc_tos(), lp_sub, snum); >+ if (conn_servicename == NULL) { >+ DBG_ERR("lp_servicename() failed, OOM!\n"); >+ return false; >+ } >+ >+ if (strequal(servicename, conn_servicename)) { >+ match = true; >+ goto done; >+ } >+ if (strequal(servicename, HOMES_NAME)) { >+ match = true; >+ goto done; >+ } >+ if (strequal(vfs_user, conn_servicename)) { >+ match = true; >+ goto done; >+ } >+done: >+ TALLOC_FREE(conn_servicename); >+ return match; >+} >+#endif >+ > /********************************************************************** > Parse a DFS pathname of the form /hostname/service/reqpath > into the dfs_path structure. >-- >2.34.1 > > >From abce1c91b18a8f2889372549398cd06c3149eb5d Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 9 Aug 2022 10:53:18 -0700 >Subject: [PATCH 11/25] s3: smbd: Use helper function > msdfs_servicename_matches_connection() in parse_dfs_path(). > >Replaces ugly complex logic. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit c0a1d7c7a8a7f24890e60c7a371498949dec11c2) >--- > source3/smbd/msdfs.c | 15 +++++++-------- > 1 file changed, 7 insertions(+), 8 deletions(-) > >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index 463601cf1ee..a48ae642ae8 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -36,7 +36,6 @@ > #include "lib/global_contexts.h" > #include "source3/lib/substitute.h" > >-#if 0 > /********************************************************************** > Function to determine if a given sharename matches a connection. > **********************************************************************/ >@@ -80,7 +79,6 @@ done: > TALLOC_FREE(conn_servicename); > return match; > } >-#endif > > /********************************************************************** > Parse a DFS pathname of the form /hostname/service/reqpath >@@ -112,14 +110,13 @@ static NTSTATUS parse_dfs_path(TALLOC_CTX *ctx, > char **_servicename, > char **_remaining_path) > { >- const struct loadparm_substitution *lp_sub = >- loadparm_s3_global_substitution(); > char *hostname = NULL; > char *pathname_local = NULL; > char *p = NULL; > char *servicename = NULL; > char *reqpath = NULL; > char *eos_ptr = NULL; >+ bool servicename_matches = false; > > pathname_local = talloc_strdup(ctx, pathname); > if (pathname_local == NULL) { >@@ -196,10 +193,12 @@ static NTSTATUS parse_dfs_path(TALLOC_CTX *ctx, > } > > /* Is this really our servicename ? */ >- if (conn && !( strequal(servicename, lp_servicename(talloc_tos(), lp_sub, SNUM(conn))) >- || (strequal(servicename, HOMES_NAME) >- && strequal(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), >- get_current_username()) )) ) { >+ servicename_matches = msdfs_servicename_matches_connection( >+ conn, >+ servicename, >+ get_current_username()); >+ >+ if (!servicename_matches) { > DBG_ERR("%s is not our servicename\n", servicename); > > /* >-- >2.34.1 > > >From e6db841b41a22c904c5effdf7c218a6d1c83a85c Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 9 Aug 2022 10:58:24 -0700 >Subject: [PATCH 12/25] s3: smbd: Use helper function > msdfs_servicename_matches_connection() in dfs_redirect(). > >Replaces ugly complex logic. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit a3c9eb7931cb4da0dd5bc5d600125979dd1a7df5) >--- > source3/smbd/msdfs.c | 13 ++++++------- > 1 file changed, 6 insertions(+), 7 deletions(-) > >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index a48ae642ae8..fce887de9aa 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -925,11 +925,10 @@ NTSTATUS dfs_redirect(TALLOC_CTX *ctx, > NTTIME *_twrp, > char **pp_path_out) > { >- const struct loadparm_substitution *lp_sub = >- loadparm_s3_global_substitution(); > char *hostname = NULL; > char *servicename = NULL; > char *reqpath = NULL; >+ bool servicename_matches = false; > NTSTATUS status; > > status = parse_dfs_path(ctx, >@@ -974,11 +973,11 @@ NTSTATUS dfs_redirect(TALLOC_CTX *ctx, > return NT_STATUS_OK; > } > >- if (!( strequal(servicename, lp_servicename(talloc_tos(), lp_sub, SNUM(conn))) >- || (strequal(servicename, HOMES_NAME) >- && strequal(lp_servicename(talloc_tos(), lp_sub, SNUM(conn)), >- conn->session_info->unix_info->sanitized_username) )) ) { >- >+ servicename_matches = msdfs_servicename_matches_connection( >+ conn, >+ servicename, >+ conn->session_info->unix_info->sanitized_username); >+ if (!servicename_matches) { > /* The given sharename doesn't match this connection. */ > return NT_STATUS_OBJECT_PATH_NOT_FOUND; > } >-- >2.34.1 > > >From b63693747ab2607debae92228b4caccf0b1a32bc Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 8 Aug 2022 11:16:17 -0700 >Subject: [PATCH 13/25] s3: smbd: Add dfs_filename_convert(). Simple wrapper > around parse_dfs_path(). > >Not yet used. > >This is what we will use to replace dfs_redirect() in the filename >conversion code. Keep as a wrapper for now as we might want to >add some error checking around the 'hostname' and 'service' >returns. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit 245d07ab84852b829c029496618e56782d070e83) >--- > source3/smbd/msdfs.c | 62 ++++++++++++++++++++++++++++++++++++++++++++ > source3/smbd/proto.h | 5 ++++ > 2 files changed, 67 insertions(+) > >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index fce887de9aa..1b66911faf0 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -902,6 +902,68 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, > return status; > } > >+/***************************************************************** >+ Decides if a dfs pathname should be redirected or not. >+ If not, the pathname is converted to a tcon-relative local unix path >+ This is now a simple wrapper around parse_dfs_path() >+ as it does all the required checks. >+*****************************************************************/ >+ >+NTSTATUS dfs_filename_convert(TALLOC_CTX *ctx, >+ connection_struct *conn, >+ uint32_t ucf_flags, >+ const char *dfs_path_in, >+ char **pp_path_out) >+{ >+ char *hostname = NULL; >+ char *servicename = NULL; >+ char *reqpath = NULL; >+ NTSTATUS status; >+ >+ status = parse_dfs_path(ctx, >+ conn, >+ dfs_path_in, >+ !conn->sconn->using_smb2, >+ &hostname, >+ &servicename, >+ &reqpath); >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; >+ } >+ >+ /* >+ * Caller doesn't care about hostname >+ * or servicename. >+ */ >+ TALLOC_FREE(hostname); >+ TALLOC_FREE(servicename); >+ >+ /* >+ * If parse_dfs_path fell back to a local path >+ * after skipping hostname or servicename, ensure >+ * we still have called check_path_syntax() >+ * on the full returned local path. check_path_syntax() >+ * is idempotent so this is safe. >+ */ >+ if (ucf_flags & UCF_POSIX_PATHNAMES) { >+ status = check_path_syntax_posix(reqpath); >+ } else { >+ status = check_path_syntax(reqpath); >+ } >+ if (!NT_STATUS_IS_OK(status)) { >+ return status; >+ } >+ /* >+ * Previous (and current logic) just ignores >+ * the server, share components if a DFS >+ * path is sent on a non-DFS share except to >+ * check that they match an existing share. Should >+ * we tighten this up to return an error here ? >+ */ >+ *pp_path_out = reqpath; >+ return NT_STATUS_OK; >+} >+ > /***************************************************************** > Decides if a dfs pathname should be redirected or not. > If not, the pathname is converted to a tcon-relative local unix path >diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h >index 33fc222311e..1c10849346e 100644 >--- a/source3/smbd/proto.h >+++ b/source3/smbd/proto.h >@@ -560,6 +560,11 @@ bool remove_msdfs_link(const struct junction_map *jucn, > struct junction_map *enum_msdfs_links(TALLOC_CTX *ctx, > struct auth_session_info *session_info, > size_t *p_num_jn); >+NTSTATUS dfs_filename_convert(TALLOC_CTX *ctx, >+ connection_struct *conn, >+ uint32_t ucf_flags, >+ const char *dfs_path_in, >+ char **pp_path_out); > NTSTATUS dfs_redirect(TALLOC_CTX *ctx, > connection_struct *conn, > const char *name_in, >-- >2.34.1 > > >From 4a23b9422dc09ca2e335b62bbc637b4809b16230 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 11 Aug 2022 23:55:58 -0700 >Subject: [PATCH 14/25] s3: smbd: In get referred_path(), make sure > check_path_syntax() is called on returned reqpath. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit da625e4ab4bc670e44fcb6ad7456aa64d0f1f9d2) >--- > source3/smbd/msdfs.c | 7 +++++++ > 1 file changed, 7 insertions(+) > >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index 1b66911faf0..19160b03c3c 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -1149,6 +1149,13 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, > return status; > } > >+ /* Path referrals are always non-POSIX. */ >+ status = check_path_syntax(reqpath); >+ if (!NT_STATUS_IS_OK(status)) { >+ TALLOC_FREE(frame); >+ return status; >+ } >+ > jucn->service_name = talloc_strdup(ctx, servicename); > jucn->volume_name = talloc_strdup(ctx, reqpath); > if (!jucn->service_name || !jucn->volume_name) { >-- >2.34.1 > > >From 0ab7eef5ccdaf4e49cfc89970546822aec593751 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Thu, 11 Aug 2022 23:57:51 -0700 >Subject: [PATCH 15/25] s3: smbd: In get create_junction(), make sure > check_path_syntax() is called on returned reqpath. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit a92f4f7af0eaa035deebfb1c930ca0cc12d992d5) >--- > source3/smbd/msdfs.c | 6 ++++++ > 1 file changed, 6 insertions(+) > >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index 19160b03c3c..5a2413ed8b9 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -1426,6 +1426,12 @@ bool create_junction(TALLOC_CTX *ctx, > return False; > } > >+ /* Junction create paths are always non-POSIX. */ >+ status = check_path_syntax(reqpath); >+ if (!NT_STATUS_IS_OK(status)) { >+ return false; >+ } >+ > jucn->service_name = talloc_strdup(ctx, servicename); > jucn->volume_name = talloc_strdup(ctx, reqpath); > jucn->comment = lp_comment(ctx, lp_sub, snum); >-- >2.34.1 > > >From 8a39ea255a897308bc816f36cbf54dc349a2a2ff Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 8 Aug 2022 11:31:39 -0700 >Subject: [PATCH 16/25] s3: smbd: Allow openat_pathref_dirfsp_nosymlink() to > return NT_STATUS_PATH_NOT_COVERED for a DFS link on a DFS share. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit b5f6809593524e7e9aca1c09ff379e02a1cde61b) >--- > source3/smbd/files.c | 12 ++++++++++++ > 1 file changed, 12 insertions(+) > >diff --git a/source3/smbd/files.c b/source3/smbd/files.c >index 1cd146dedc7..72d1bc7d555 100644 >--- a/source3/smbd/files.c >+++ b/source3/smbd/files.c >@@ -856,6 +856,18 @@ next: > *unparsed = len - parsed; > } > } >+ /* >+ * If we're on an MSDFS share, see if this is >+ * an MSDFS link. >+ */ >+ if (lp_host_msdfs() && >+ lp_msdfs_root(SNUM(conn)) && >+ (substitute != NULL) && >+ strnequal(*substitute, "msdfs:", 6) && >+ is_msdfs_link(dirfsp, &rel_fname)) >+ { >+ status = NT_STATUS_PATH_NOT_COVERED; >+ } > } else { > > DBG_DEBUG("readlink_talloc failed: %s\n", >-- >2.34.1 > > >From e26307c6830afc3c3e97519aa0bfef31ea961d43 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 8 Aug 2022 13:15:17 -0700 >Subject: [PATCH 17/25] s3: smbd: In filename_convert_dirfsp_nosymlink(), allow > a NT_STATUS_PATH_NOT_COVERED error to be returned. > >openat_pathref_dirfsp_nosymlink() can now return NT_STATUS_PATH_NOT_COVERED. >Don't convert this automatically into NT_STATUS_OBJECT_PATH_NOT_FOUND. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit 07ef9e3029b8cca1b92d900d6ed684ca0ac6afe4) >--- > source3/smbd/filename.c | 5 +++++ > 1 file changed, 5 insertions(+) > >diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c >index 87abc8be376..41144097362 100644 >--- a/source3/smbd/filename.c >+++ b/source3/smbd/filename.c >@@ -2549,6 +2549,11 @@ static NTSTATUS filename_convert_dirfsp_nosymlink( > nt_errstr(status)); > TALLOC_FREE(dirname); > >+ if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) { >+ /* MS-DFS error must propagate back out. */ >+ goto fail; >+ } >+ > if (!NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { > /* > * Except ACCESS_DENIED, everything else leads >-- >2.34.1 > > >From 215f7160505f0956ad3753296f80c7e49c613678 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 8 Aug 2022 13:18:56 -0700 >Subject: [PATCH 18/25] s3: smbd: In filename_convert_dirfsp_nosymlink(), cope > with an MS-DFS link as the terminal component. > >If the terminal component was an MSDFS link, openat_pathref_fsp_case_insensitive() will >return NT_STATUS_OBJECT_NAME_NOT_FOUND with a VALID_STAT of a symlink. > >If this is the case, check if we actually found a terminal MS-DFS link >at the end of the pathname and return NT_STATUS_PATH_NOT_COVERED. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit d80bedc3c418b6839b1bde78ba8d3db06611be2a) >--- > source3/smbd/filename.c | 13 +++++++++++++ > 1 file changed, 13 insertions(+) > >diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c >index 41144097362..3e7909a48c8 100644 >--- a/source3/smbd/filename.c >+++ b/source3/smbd/filename.c >@@ -2635,6 +2635,19 @@ static NTSTATUS filename_convert_dirfsp_nosymlink( > char *normalized = NULL; > > if (VALID_STAT(smb_fname_rel->st)) { >+ /* >+ * If we're on an MSDFS share, see if this is >+ * an MSDFS link. >+ */ >+ if (lp_host_msdfs() && >+ lp_msdfs_root(SNUM(conn)) && >+ S_ISLNK(smb_fname_rel->st.st_ex_mode) && >+ is_msdfs_link(smb_dirname->fsp, smb_fname_rel)) >+ { >+ status = NT_STATUS_PATH_NOT_COVERED; >+ goto fail; >+ } >+ > #if defined(WITH_SMB1SERVER) > /* > * In SMB1 posix mode, if this is a symlink, >-- >2.34.1 > > >From 77ae9545f38f817e6515d117e00648b71887d4ba Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Wed, 10 Aug 2022 11:29:33 -0700 >Subject: [PATCH 19/25] s3: smbd: Remove call to dfs_redirect() from > filename_convert_smb1_search_path(). > >Use dfs_filename_convert() instead. Code is now much simpler. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit fcf19d91c09edc6dfbf5bd7cbeedcd641030eb31) >--- > source3/smbd/filename.c | 68 ++++++++--------------------------------- > 1 file changed, 12 insertions(+), 56 deletions(-) > >diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c >index 3e7909a48c8..cba012acc3e 100644 >--- a/source3/smbd/filename.c >+++ b/source3/smbd/filename.c >@@ -1935,67 +1935,23 @@ NTSTATUS filename_convert_smb1_search_path(TALLOC_CTX *ctx, > /* > * We've been given a raw DFS pathname. > */ >- char *fname = NULL; >- char *name_in_copy = NULL; >- char *last_component = NULL; >- >- /* Work on a copy of name_in. */ >- name_in_copy = talloc_strdup(ctx, name_in); >- if (name_in_copy == NULL) { >- return NT_STATUS_NO_MEMORY; >- } >- >- /* >- * Now we know that the last component is the >- * wildcard. Copy it and truncate to remove it. >- */ >- p = strrchr(name_in_copy, '/'); >- if (p == NULL) { >- last_component = talloc_strdup(ctx, name_in_copy); >- name_in_copy[0] = '\0'; >- } else { >- last_component = talloc_strdup(ctx, p+1); >- *p = '\0'; >- } >- if (last_component == NULL) { >- return NT_STATUS_NO_MEMORY; >- } >- >- DBG_DEBUG("name_in_copy: %s\n", name_in_copy); >- >- /* >- * Now we can call dfs_redirect() >- * on the name without wildcard. >- */ >- status = dfs_redirect(ctx, >- conn, >- name_in_copy, >- ucf_flags, >- !conn->sconn->using_smb2, >- NULL, >- &fname); >- if (!NT_STATUS_IS_OK(status)) { >- DBG_DEBUG("dfs_redirect " >+ char *pathname = NULL; >+ DBG_DEBUG("Before dfs_filename_convert name_in: %s\n", name_in); >+ status = dfs_filename_convert(ctx, >+ conn, >+ ucf_flags, >+ name_in, >+ &pathname); >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG_DEBUG("dfs_filename_convert " > "failed for name %s with %s\n", >- name_in_copy, >+ name_in, > nt_errstr(status)); > return status; > } >- /* Add the last component back. */ >- if (fname[0] == '\0') { >- name_in = talloc_strdup(ctx, last_component); >- } else { >- name_in = talloc_asprintf(ctx, >- "%s/%s", >- fname, >- last_component); >- } >- if (name_in == NULL) { >- return NT_STATUS_NO_MEMORY; >- } > ucf_flags &= ~UCF_DFS_PATHNAME; >- >- DBG_DEBUG("After DFS redirect name_in: %s\n", name_in); >+ name_in = pathname; >+ DBG_DEBUG("After dfs_filename_convert name_in: %s\n", name_in); > } > > /* Get the original lcomp. */ >-- >2.34.1 > > >From 0ce8a97c18632a3abeda395431fe0d0631259b29 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Wed, 10 Aug 2022 11:32:30 -0700 >Subject: [PATCH 20/25] s3: smbd: Remove call to dfs_redirect() from > filename_convert_dirfsp_nosymlink(). > >Use dfs_filename_convert() instead. There are now no more callers of dfs_redirect(). > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit d20b60c3200b5e1881cdf4b59da154d1af7e3994) >--- > source3/smbd/filename.c | 28 +++++++++++++--------------- > 1 file changed, 13 insertions(+), 15 deletions(-) > >diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c >index cba012acc3e..b64fb908f16 100644 >--- a/source3/smbd/filename.c >+++ b/source3/smbd/filename.c >@@ -2384,28 +2384,26 @@ static NTSTATUS filename_convert_dirfsp_nosymlink( > NTSTATUS status = NT_STATUS_UNSUCCESSFUL; > > if (ucf_flags & UCF_DFS_PATHNAME) { >- char *fname = NULL; >- NTTIME dfs_twrp = 0; >- status = dfs_redirect( >- mem_ctx, >- conn, >- name_in, >- ucf_flags, >- !conn->sconn->using_smb2, >- &dfs_twrp, >- &fname); >+ /* >+ * We've been given a raw DFS pathname. >+ */ >+ char *pathname = NULL; >+ DBG_DEBUG("Before dfs_filename_convert name_in: %s\n", name_in); >+ status = dfs_filename_convert(mem_ctx, >+ conn, >+ ucf_flags, >+ name_in, >+ &pathname); > if (!NT_STATUS_IS_OK(status)) { >- DBG_DEBUG("dfs_redirect " >+ DBG_DEBUG("dfs_filename_convert " > "failed for name %s with %s\n", > name_in, > nt_errstr(status)); > return status; > } >- name_in = fname; > ucf_flags &= ~UCF_DFS_PATHNAME; >- if (twrp == 0 && dfs_twrp != 0) { >- twrp = dfs_twrp; >- } >+ name_in = pathname; >+ DBG_DEBUG("After dfs_filename_convert name_in: %s\n", name_in); > } > > if (is_fake_file_path(name_in)) { >-- >2.34.1 > > >From 8c469cafeb9944af7a1882f570f1acc4d52babf3 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Wed, 10 Aug 2022 11:34:24 -0700 >Subject: [PATCH 21/25] s3: smbd: Remove dfs_redirect(). > >A moment of silence please. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit 6b1224b22012b54b1ae20b682daf61c877362a7b) >--- > source3/smbd/msdfs.c | 115 ------------------------------------------- > source3/smbd/proto.h | 7 --- > 2 files changed, 122 deletions(-) > >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index 5a2413ed8b9..d48c5d6c906 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -964,121 +964,6 @@ NTSTATUS dfs_filename_convert(TALLOC_CTX *ctx, > return NT_STATUS_OK; > } > >-/***************************************************************** >- Decides if a dfs pathname should be redirected or not. >- If not, the pathname is converted to a tcon-relative local unix path >- >- search_wcard_flag: this flag performs 2 functions both related >- to searches. See resolve_dfs_path() and parse_dfs_path_XX() >- for details. >- >- This function can return NT_STATUS_OK, meaning use the returned path as-is >- (mapped into a local path). >- or NT_STATUS_NOT_COVERED meaning return a DFS redirect, or >- any other NT_STATUS error which is a genuine error to be >- returned to the client. >-*****************************************************************/ >- >-NTSTATUS dfs_redirect(TALLOC_CTX *ctx, >- connection_struct *conn, >- const char *path_in, >- uint32_t ucf_flags, >- bool allow_broken_path, >- NTTIME *_twrp, >- char **pp_path_out) >-{ >- char *hostname = NULL; >- char *servicename = NULL; >- char *reqpath = NULL; >- bool servicename_matches = false; >- NTSTATUS status; >- >- status = parse_dfs_path(ctx, >- conn, >- path_in, >- allow_broken_path, >- &hostname, >- &servicename, >- &reqpath); >- if (!NT_STATUS_IS_OK(status)) { >- return status; >- } >- >- if (reqpath[0] == '\0') { >- *pp_path_out = talloc_strdup(ctx, ""); >- if (!*pp_path_out) { >- return NT_STATUS_NO_MEMORY; >- } >- DEBUG(5,("dfs_redirect: self-referral.\n")); >- return NT_STATUS_OK; >- } >- >- /* If dfs pathname for a non-dfs share, convert to tcon-relative >- path and return OK */ >- >- if (!lp_msdfs_root(SNUM(conn))) { >- *pp_path_out = talloc_strdup(ctx, reqpath); >- if (!*pp_path_out) { >- return NT_STATUS_NO_MEMORY; >- } >- return NT_STATUS_OK; >- } >- >- /* If it looked like a local path (zero hostname/servicename) >- * just treat as a tcon-relative path. */ >- >- if (hostname[0] == '\0' && servicename[0] == '\0') { >- *pp_path_out = talloc_strdup(ctx, reqpath); >- if (!*pp_path_out) { >- return NT_STATUS_NO_MEMORY; >- } >- return NT_STATUS_OK; >- } >- >- servicename_matches = msdfs_servicename_matches_connection( >- conn, >- servicename, >- conn->session_info->unix_info->sanitized_username); >- if (!servicename_matches) { >- /* The given sharename doesn't match this connection. */ >- return NT_STATUS_OBJECT_PATH_NOT_FOUND; >- } >- >- status = dfs_path_lookup(ctx, >- conn, >- path_in, >- reqpath, >- ucf_flags, >- _twrp, /* twrp. */ >- NULL, /* size_t *consumedcntp */ >- NULL, /* struct referral **ppreflist */ >- NULL); /* size_t *preferral_count */ >- if (!NT_STATUS_IS_OK(status)) { >- if (NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) { >- DEBUG(3,("dfs_redirect: Redirecting %s\n", path_in)); >- } else { >- DEBUG(10,("dfs_redirect: dfs_path_lookup " >- "failed for %s with %s\n", >- path_in, nt_errstr(status) )); >- } >- return status; >- } >- >- DEBUG(3,("dfs_redirect: Not redirecting %s.\n", path_in)); >- >- /* Form non-dfs tcon-relative path */ >- *pp_path_out = talloc_strdup(ctx, reqpath); >- if (!*pp_path_out) { >- return NT_STATUS_NO_MEMORY; >- } >- >- DEBUG(3,("dfs_redirect: Path %s converted to non-dfs path %s\n", >- path_in, >- *pp_path_out)); >- >- return NT_STATUS_OK; >-} >- > /********************************************************************** > Return a self referral. > **********************************************************************/ >diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h >index 1c10849346e..bc305bce296 100644 >--- a/source3/smbd/proto.h >+++ b/source3/smbd/proto.h >@@ -565,13 +565,6 @@ NTSTATUS dfs_filename_convert(TALLOC_CTX *ctx, > uint32_t ucf_flags, > const char *dfs_path_in, > char **pp_path_out); >-NTSTATUS dfs_redirect(TALLOC_CTX *ctx, >- connection_struct *conn, >- const char *name_in, >- uint32_t ucf_flags, >- bool allow_broken_path, >- NTTIME *twrp, >- char **pp_name_out); > struct connection_struct; > struct smb_filename; > >-- >2.34.1 > > >From f1e52f44d3961ed4d3319b158106edc13a0aa918 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 9 Aug 2022 12:07:30 -0700 >Subject: [PATCH 22/25] s3: smbd: Add new version of dfs_path_lookup() that > uses filename_convert_dirfsp(). > >Commented out as not yet used but it's easier to see the >new logic this way. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit 22d4f62537199d9454be312a546e251f04022497) >--- > source3/smbd/msdfs.c | 261 +++++++++++++++++++++++++++++++++++++++++++ > 1 file changed, 261 insertions(+) > >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index d48c5d6c906..ab7f9f0ad78 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -713,6 +713,267 @@ bool is_msdfs_link(struct files_struct *dirfsp, > return (NT_STATUS_IS_OK(status)); > } > >+#if 0 >+/***************************************************************** >+ Used by other functions to decide if a dfs path is remote, >+ and to get the list of referred locations for that remote path. >+ >+ consumedcntp: how much of the dfs path is being redirected. the client >+ should try the remaining path on the redirected server. >+*****************************************************************/ >+ >+static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, >+ connection_struct *conn, >+ const char *dfspath, /* Incoming complete dfs path */ >+ const char *reqpath, /* Parsed out remaining path. */ >+ uint32_t ucf_flags, >+ size_t *consumedcntp, >+ struct referral **ppreflist, >+ size_t *preferral_count) >+{ >+ NTSTATUS status; >+ struct smb_filename *parent_smb_fname = NULL; >+ struct smb_filename *smb_fname_rel = NULL; >+ NTTIME twrp = 0; >+ char *local_pathname = NULL; >+ char *last_component = NULL; >+ char *atname = NULL; >+ size_t removed_components = 0; >+ bool posix = (ucf_flags & UCF_POSIX_PATHNAMES); >+ char *p = NULL; >+ char *canon_dfspath = NULL; >+ >+ DBG_DEBUG("Conn path = %s reqpath = %s\n", conn->connectpath, reqpath); >+ >+ local_pathname = talloc_strdup(ctx, reqpath); >+ if (local_pathname == NULL) { >+ status = NT_STATUS_NO_MEMORY; >+ goto out; >+ } >+ >+ /* We know reqpath isn't a DFS path. */ >+ ucf_flags &= ~UCF_DFS_PATHNAME; >+ >+ if (ucf_flags & UCF_GMT_PATHNAME) { >+ extract_snapshot_token(local_pathname, &twrp); >+ ucf_flags &= ~UCF_GMT_PATHNAME; >+ } >+ >+ /* >+ * We should have been given a DFS path to resolve. >+ * This should return NT_STATUS_PATH_NOT_COVERED. >+ * >+ * Do a pathname walk, stripping off components >+ * until we get NT_STATUS_OK instead of >+ * NT_STATUS_PATH_NOT_COVERED. >+ * >+ * Fail on any other error. >+ */ >+ >+ for (;;) { >+ TALLOC_CTX *frame = NULL; >+ struct files_struct *dirfsp = NULL; >+ struct smb_filename *smb_fname_walk = NULL; >+ >+ TALLOC_FREE(parent_smb_fname); >+ >+ /* >+ * Use a local stackframe as filename_convert_dirfsp() >+ * opens handles on the last two components in the path. >+ * Allow these to be freed as we step back through >+ * the local_pathname. >+ */ >+ frame = talloc_stackframe(); >+ status = filename_convert_dirfsp(frame, >+ conn, >+ local_pathname, >+ ucf_flags, >+ twrp, >+ &dirfsp, >+ &smb_fname_walk); >+ /* If we got a name, save it. */ >+ if (smb_fname_walk != NULL) { >+ parent_smb_fname = talloc_move(ctx, &smb_fname_walk); >+ } >+ TALLOC_FREE(frame); >+ >+ if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) { >+ /* >+ * For any other status than NT_STATUS_PATH_NOT_COVERED >+ * (including NT_STATUS_OK) we exit the walk. >+ * If it's an error we catch it outside the loop. >+ */ >+ break; >+ } >+ >+ /* Step back one component and save it off as last_component. */ >+ TALLOC_FREE(last_component); >+ p = strrchr(local_pathname, '/'); >+ if (p == NULL) { >+ /* >+ * We removed all components. >+ * Go around once more to make >+ * sure we can open the root '\0'. >+ */ >+ last_component = talloc_strdup(ctx, local_pathname); >+ *local_pathname = '\0'; >+ } else { >+ last_component = talloc_strdup(ctx, p+1); >+ *p = '\0'; >+ } >+ if (last_component == NULL) { >+ status = NT_STATUS_NO_MEMORY; >+ goto out; >+ } >+ /* Integer wrap check. */ >+ if (removed_components + 1 < removed_components) { >+ status = NT_STATUS_INVALID_PARAMETER; >+ goto out; >+ } >+ removed_components++; >+ } >+ >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG_DEBUG("dfspath = %s. reqpath = %s. Error %s.\n", >+ dfspath, >+ reqpath, >+ nt_errstr(status)); >+ goto out; >+ } >+ >+ if (parent_smb_fname->fsp == NULL) { >+ /* Unable to open parent. */ >+ DBG_DEBUG("dfspath = %s. reqpath = %s. " >+ "Unable to open parent directory (%s).\n", >+ dfspath, >+ reqpath, >+ smb_fname_str_dbg(parent_smb_fname)); >+ status = NT_STATUS_OBJECT_PATH_NOT_FOUND; >+ goto out; >+ } >+ >+ if (removed_components == 0) { >+ /* >+ * We never got NT_STATUS_PATH_NOT_COVERED. >+ * There was no DFS redirect. >+ */ >+ DBG_DEBUG("dfspath = %s. reqpath = %s. " >+ "No removed components.\n", >+ dfspath, >+ reqpath); >+ status = NT_STATUS_OBJECT_PATH_NOT_FOUND; >+ goto out; >+ } >+ >+ /* >+ * One of the removed_components was the MSDFS link >+ * at the end. We need to count this in the resolved >+ * path below, so remove one from removed_components. >+ */ >+ removed_components--; >+ >+ /* >+ * Now parent_smb_fname->fsp is the parent directory dirfsp, >+ * last_component is the untranslated MS-DFS link name. >+ * Search for it in the parent directory to get the real >+ * filename on disk. >+ */ >+ status = get_real_filename_at(parent_smb_fname->fsp, >+ last_component, >+ ctx, >+ &atname); >+ >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG_DEBUG("dfspath = %s. reqpath = %s " >+ "get_real_filename_at(%s, %s) error (%s)\n", >+ dfspath, >+ reqpath, >+ smb_fname_str_dbg(parent_smb_fname), >+ last_component, >+ nt_errstr(status)); >+ goto out; >+ } >+ >+ smb_fname_rel = synthetic_smb_fname(ctx, >+ atname, >+ NULL, >+ NULL, >+ twrp, >+ posix ? SMB_FILENAME_POSIX_PATH : 0); >+ if (smb_fname_rel == NULL) { >+ status = NT_STATUS_NO_MEMORY; >+ goto out; >+ } >+ >+ /* Get the referral to return. */ >+ status = SMB_VFS_READ_DFS_PATHAT(conn, >+ ctx, >+ parent_smb_fname->fsp, >+ smb_fname_rel, >+ ppreflist, >+ preferral_count); >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG_DEBUG("dfspath = %s. reqpath = %s. " >+ "SMB_VFS_READ_DFS_PATHAT(%s, %s) error (%s)\n", >+ dfspath, >+ reqpath, >+ smb_fname_str_dbg(parent_smb_fname), >+ smb_fname_str_dbg(smb_fname_rel), >+ nt_errstr(status)); >+ goto out; >+ } >+ >+ /* >+ * Now we must work out how much of the >+ * given pathname we consumed. >+ */ >+ canon_dfspath = talloc_strdup(ctx, dfspath); >+ if (!canon_dfspath) { >+ status = NT_STATUS_NO_MEMORY; >+ goto out; >+ } >+ /* Canonicalize the raw dfspath. */ >+ string_replace(canon_dfspath, '\\', '/'); >+ >+ /* >+ * reqpath comes out of parse_dfs_path(), so it has >+ * no trailing backslash. Make sure that canon_dfspath hasn't either. >+ */ >+ trim_char(canon_dfspath, 0, '/'); >+ >+ DBG_DEBUG("Unconsumed path: %s\n", canon_dfspath); >+ >+ while (removed_components > 0) { >+ p = strrchr(canon_dfspath, '/'); >+ if (p != NULL) { >+ *p = '\0'; >+ } >+ removed_components--; >+ if (p == NULL && removed_components != 0) { >+ DBG_ERR("Component missmatch. path = %s, " >+ "%zu components left\n", >+ canon_dfspath, >+ removed_components); >+ status = NT_STATUS_OBJECT_PATH_NOT_FOUND; >+ goto out; >+ } >+ } >+ *consumedcntp = strlen(canon_dfspath); >+ DBG_DEBUG("Path consumed: %s (%zu)\n", canon_dfspath, *consumedcntp); >+ status = NT_STATUS_OK; >+ >+ out: >+ >+ TALLOC_FREE(parent_smb_fname); >+ TALLOC_FREE(local_pathname); >+ TALLOC_FREE(last_component); >+ TALLOC_FREE(atname); >+ TALLOC_FREE(smb_fname_rel); >+ TALLOC_FREE(canon_dfspath); >+ return status; >+} >+#endif >+ > /***************************************************************** > Used by other functions to decide if a dfs path is remote, > and to get the list of referred locations for that remote path. >-- >2.34.1 > > >From ce38e08e1449f275a2a98a74d41ec8906f831aa5 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 9 Aug 2022 12:11:07 -0700 >Subject: [PATCH 23/25] s3: smbd: Switch get_referred_path() over to use the > new dfs_path_lookup(). > >New function doesn't need a TWRP argument and returns NT_STATUS_OK >on successful redirect, not NT_STATUS_PATH_NOT_COVERED. > >Comment out the old dfs_path_lookup(). > >There are now no more users of unix_convert(). > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit 88e8bfec59412fdc0e83251fef60b45d2cc3a884) >--- > source3/smbd/msdfs.c | 31 ++++++------------------------- > 1 file changed, 6 insertions(+), 25 deletions(-) > >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index ab7f9f0ad78..55ab12a75e3 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -713,7 +713,6 @@ bool is_msdfs_link(struct files_struct *dirfsp, > return (NT_STATUS_IS_OK(status)); > } > >-#if 0 > /***************************************************************** > Used by other functions to decide if a dfs path is remote, > and to get the list of referred locations for that remote path. >@@ -972,8 +971,8 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, > TALLOC_FREE(canon_dfspath); > return status; > } >-#endif > >+#if 0 > /***************************************************************** > Used by other functions to decide if a dfs path is remote, > and to get the list of referred locations for that remote path. >@@ -1162,6 +1161,7 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, > TALLOC_FREE(smb_fname); > return status; > } >+#endif > > /***************************************************************** > Decides if a dfs pathname should be redirected or not. >@@ -1420,40 +1420,21 @@ NTSTATUS get_referred_path(TALLOC_CTX *ctx, > } > } > >- /* If this is a DFS path dfs_lookup should return >- * NT_STATUS_PATH_NOT_COVERED. */ >- > status = dfs_path_lookup(ctx, > conn, > dfs_path, > reqpath, > 0, /* ucf_flags */ >- NULL, > consumedcntp, > &jucn->referral_list, > &jucn->referral_count); > >- if (!NT_STATUS_EQUAL(status, NT_STATUS_PATH_NOT_COVERED)) { >- DEBUG(3,("get_referred_path: No valid referrals for path %s\n", >- dfs_path)); >- if (NT_STATUS_IS_OK(status)) { >- /* >- * We are in an error path here (we >- * know it's not a DFS path), but >- * dfs_path_lookup() can return >- * NT_STATUS_OK. Ensure we always >- * return a valid error code. >- * >- * #9588 - ACLs are not inherited to directories >- * for DFS shares. >- */ >- status = NT_STATUS_NOT_FOUND; >- } >- goto err_exit; >+ if (!NT_STATUS_IS_OK(status)) { >+ DBG_NOTICE("No valid referrals for path %s (%s)\n", >+ dfs_path, >+ nt_errstr(status)); > } > >- status = NT_STATUS_OK; >- err_exit: > TALLOC_FREE(frame); > return status; > } >-- >2.34.1 > > >From 3b266f1ff88b10fc62ff12f8f9f374dbb0b1bed1 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Tue, 9 Aug 2022 12:13:10 -0700 >Subject: [PATCH 24/25] s3: smbd: Remove the old dfs_path_lookup() code. > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> >(cherry picked from commit cc638c25e0332d366016880d174d9349940cba3f) >--- > source3/smbd/msdfs.c | 191 ------------------------------------------- > 1 file changed, 191 deletions(-) > >diff --git a/source3/smbd/msdfs.c b/source3/smbd/msdfs.c >index 55ab12a75e3..4819df35837 100644 >--- a/source3/smbd/msdfs.c >+++ b/source3/smbd/msdfs.c >@@ -972,197 +972,6 @@ static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, > return status; > } > >-#if 0 >-/***************************************************************** >- Used by other functions to decide if a dfs path is remote, >- and to get the list of referred locations for that remote path. >- >- consumedcntp: how much of the dfs path is being redirected. the client >- should try the remaining path on the redirected server. >- >- If this returns NT_STATUS_PATH_NOT_COVERED the contents of the msdfs >- link redirect are in targetpath. >-*****************************************************************/ >- >-static NTSTATUS dfs_path_lookup(TALLOC_CTX *ctx, >- connection_struct *conn, >- const char *dfspath, /* Incoming complete dfs path */ >- const char *reqpath, /* Parsed out remaining path. */ >- uint32_t ucf_flags, >- NTTIME *_twrp, >- size_t *consumedcntp, >- struct referral **ppreflist, >- size_t *preferral_count) >-{ >- char *p = NULL; >- char *q = NULL; >- NTSTATUS status; >- struct smb_filename *smb_fname = NULL; >- struct smb_filename *parent_fname = NULL; >- struct smb_filename *atname = NULL; >- char *canon_dfspath = NULL; /* Canonicalized dfs path. (only '/' >- components). */ >- >- DEBUG(10,("dfs_path_lookup: Conn path = %s reqpath = %s\n", >- conn->connectpath, reqpath)); >- >- /* >- * Note the unix path conversion here we're doing we >- * throw away. We're looking for a symlink for a dfs >- * resolution, if we don't find it we'll do another >- * unix_convert later in the codepath. >- */ >- >- status = unix_convert(ctx, conn, reqpath, 0, &smb_fname, >- ucf_flags); >- >- if (!NT_STATUS_IS_OK(status)) { >- if (!NT_STATUS_EQUAL(status, >- NT_STATUS_OBJECT_PATH_NOT_FOUND)) { >- return status; >- } >- if (smb_fname == NULL || smb_fname->base_name == NULL) { >- return status; >- } >- } >- >- /* Optimization - check if we can redirect the whole path. */ >- status = parent_pathref(ctx, >- conn->cwd_fsp, >- smb_fname, >- &parent_fname, >- &atname); >- if (NT_STATUS_IS_OK(status)) { >- /* >- * We must have a parent_fname->fsp before >- * we can call SMB_VFS_READ_DFS_PATHAT(). >- */ >- status = SMB_VFS_READ_DFS_PATHAT(conn, >- ctx, >- parent_fname->fsp, >- atname, >- ppreflist, >- preferral_count); >- /* We're now done with parent_fname and atname. */ >- TALLOC_FREE(parent_fname); >- >- if (NT_STATUS_IS_OK(status)) { >- DBG_INFO("%s resolves to a valid dfs link\n", >- dfspath); >- >- if (consumedcntp) { >- *consumedcntp = strlen(dfspath); >- } >- status = NT_STATUS_PATH_NOT_COVERED; >- goto out; >- } >- } >- >- /* Prepare to test only for '/' components in the given path, >- * so if a Windows path replace all '\\' characters with '/'. >- * For a POSIX DFS path we know all separators are already '/'. */ >- >- canon_dfspath = talloc_strdup(ctx, dfspath); >- if (!canon_dfspath) { >- status = NT_STATUS_NO_MEMORY; >- goto out; >- } >- string_replace(canon_dfspath, '\\', '/'); >- >- /* >- * localpath comes out of unix_convert, so it has >- * no trailing backslash. Make sure that canon_dfspath hasn't either. >- * Fix for bug #4860 from Jan Martin <Jan.Martin@rwedea.com>. >- */ >- >- trim_char(canon_dfspath,0,'/'); >- >- /* >- * Redirect if any component in the path is a link. >- * We do this by walking backwards through the >- * local path, chopping off the last component >- * in both the local path and the canonicalized >- * DFS path. If we hit a DFS link then we're done. >- */ >- >- p = strrchr_m(smb_fname->base_name, '/'); >- if (consumedcntp) { >- q = strrchr_m(canon_dfspath, '/'); >- } >- >- while (p) { >- *p = '\0'; >- if (q) { >- *q = '\0'; >- } >- >- /* >- * Ensure parent_pathref() calls vfs_stat() on >- * the newly truncated path. >- */ >- SET_STAT_INVALID(smb_fname->st); >- status = parent_pathref(ctx, >- conn->cwd_fsp, >- smb_fname, >- &parent_fname, >- &atname); >- if (NT_STATUS_IS_OK(status)) { >- /* >- * We must have a parent_fname->fsp before >- * we can call SMB_VFS_READ_DFS_PATHAT(). >- */ >- status = SMB_VFS_READ_DFS_PATHAT(conn, >- ctx, >- parent_fname->fsp, >- atname, >- ppreflist, >- preferral_count); >- >- /* We're now done with parent_fname and atname. */ >- TALLOC_FREE(parent_fname); >- >- if (NT_STATUS_IS_OK(status)) { >- DBG_INFO("Redirecting %s because " >- "parent %s is a dfs link\n", >- dfspath, >- smb_fname_str_dbg(smb_fname)); >- >- if (consumedcntp) { >- *consumedcntp = strlen(canon_dfspath); >- DBG_DEBUG("Path consumed: %s " >- "(%zu)\n", >- canon_dfspath, >- *consumedcntp); >- } >- >- status = NT_STATUS_PATH_NOT_COVERED; >- goto out; >- } >- } >- >- /* Step back on the filesystem. */ >- p = strrchr_m(smb_fname->base_name, '/'); >- >- if (consumedcntp) { >- /* And in the canonicalized dfs path. */ >- q = strrchr_m(canon_dfspath, '/'); >- } >- } >- >- if ((ucf_flags & UCF_GMT_PATHNAME) && _twrp != NULL) { >- *_twrp = smb_fname->twrp; >- } >- >- status = NT_STATUS_OK; >- out: >- >- /* This should already be free, but make sure. */ >- TALLOC_FREE(parent_fname); >- TALLOC_FREE(smb_fname); >- return status; >-} >-#endif >- > /***************************************************************** > Decides if a dfs pathname should be redirected or not. > If not, the pathname is converted to a tcon-relative local unix path >-- >2.34.1 > > >From 74eb042edab52463ba735af3d590dad244eb4f99 Mon Sep 17 00:00:00 2001 >From: Jeremy Allison <jra@samba.org> >Date: Mon, 8 Aug 2022 21:59:14 -0700 >Subject: [PATCH 25/25] s3: smbd: Remove unix_convert() and associated > functions. > >All code now uses filename_convert_dirfsp() for race-free >filename conversion. > >Best viewed with: >$ git show --patience > > ---------------- > / \ > / REST \ > / IN \ > / PEACE \ > / \ > | | > | unix_convert | > | | > | | > | 9th August | > | 2022 | > | | > | | > *| * * * | * >_________)/\\_//(\/(/\)/\//\/\///\/|_)_______ > >BUG: https://bugzilla.samba.org/show_bug.cgi?id=15144 > >Signed-off-by: Jeremy Allison <jra@samba.org> >Reviewed-by: Ralph Boehme <slow@samba.org> > >Autobuild-User(master): Jeremy Allison <jra@samba.org> >Autobuild-Date(master): Fri Aug 12 19:18:25 UTC 2022 on sn-devel-184 > >(cherry picked from commit 78e4aac76df977cea6cdbcfdf082fd3acdffbd95) >--- > source3/smbd/filename.c | 1565 +++------------------------------------ > source3/smbd/proto.h | 12 - > 2 files changed, 107 insertions(+), 1470 deletions(-) > >diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c >index b64fb908f16..f362aee9452 100644 >--- a/source3/smbd/filename.c >+++ b/source3/smbd/filename.c >@@ -31,15 +31,6 @@ > #include "smbd/globals.h" > #include "lib/util/memcache.h" > >-static NTSTATUS get_real_filename(connection_struct *conn, >- struct smb_filename *path, >- const char *name, >- TALLOC_CTX *mem_ctx, >- char **found_name); >- >-static NTSTATUS check_name(connection_struct *conn, >- const struct smb_filename *smb_fname); >- > uint32_t ucf_flags_from_smb_request(struct smb_request *req) > { > uint32_t ucf_flags = 0; >@@ -80,10 +71,6 @@ uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disp > return ucf_flags; > } > >-static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, >- connection_struct *conn, >- struct smb_filename *smb_fname); >- > /**************************************************************************** > Mangle the 2nd name and check if it is then equal to the first name. > ****************************************************************************/ >@@ -100,153 +87,6 @@ static bool mangled_equal(const char *name1, > return strequal(name1, mname); > } > >-static NTSTATUS check_for_dot_component(const struct smb_filename *smb_fname) >-{ >- /* Ensure we catch all names with in "/." >- this is disallowed under Windows and >- in POSIX they've already been removed. */ >- const char *p = strstr(smb_fname->base_name, "/."); /*mb safe*/ >- if (p) { >- if (p[2] == '/') { >- /* Error code within a pathname. */ >- return NT_STATUS_OBJECT_PATH_NOT_FOUND; >- } else if (p[2] == '\0') { >- /* Error code at the end of a pathname. */ >- return NT_STATUS_OBJECT_NAME_INVALID; >- } >- } >- return NT_STATUS_OK; >-} >- >-/**************************************************************************** >- Optimization for common case where the missing part >- is in the last component and the client already >- sent the correct case. >- Returns NT_STATUS_OK to mean continue the tree walk >- (possibly with modified start pointer). >- Any other NT_STATUS_XXX error means terminate the path >- lookup here. >-****************************************************************************/ >- >-static NTSTATUS check_parent_exists(TALLOC_CTX *ctx, >- connection_struct *conn, >- bool posix_pathnames, >- const struct smb_filename *smb_fname, >- char **pp_dirpath, >- char **pp_start, >- int *p_parent_stat_errno) >-{ >- char *parent_name = NULL; >- struct smb_filename *parent_fname = NULL; >- const char *last_component = NULL; >- NTSTATUS status; >- int ret; >- >- if (!parent_dirname(ctx, smb_fname->base_name, >- &parent_name, >- &last_component)) { >- return NT_STATUS_NO_MEMORY; >- } >- >- if (!posix_pathnames) { >- if (ms_has_wild(parent_name)) { >- goto no_optimization_out; >- } >- } >- >- /* >- * If there was no parent component in >- * smb_fname->base_name then don't do this >- * optimization. >- */ >- if (smb_fname->base_name == last_component) { >- goto no_optimization_out; >- } >- >- parent_fname = synthetic_smb_fname(ctx, >- parent_name, >- NULL, >- NULL, >- smb_fname->twrp, >- smb_fname->flags); >- if (parent_fname == NULL) { >- return NT_STATUS_NO_MEMORY; >- } >- >- ret = vfs_stat(conn, parent_fname); >- >- /* If the parent stat failed, just continue >- with the normal tree walk. */ >- >- if (ret == -1) { >- /* >- * Optimization. Preserving the >- * errno from the STAT/LSTAT here >- * will allow us to save a duplicate >- * STAT/LSTAT system call of the parent >- * pathname in a hot code path in the caller. >- */ >- if (p_parent_stat_errno != NULL) { >- *p_parent_stat_errno = errno; >- } >- goto no_optimization_out; >- } >- >- status = check_for_dot_component(parent_fname); >- if (!NT_STATUS_IS_OK(status)) { >- return status; >- } >- >- /* Parent exists - set "start" to be the >- * last component to shorten the tree walk. */ >- >- /* >- * Safe to use discard_const_p >- * here as last_component points >- * into our smb_fname->base_name. >- */ >- *pp_start = discard_const_p(char, last_component); >- >- /* Update dirpath. */ >- TALLOC_FREE(*pp_dirpath); >- *pp_dirpath = talloc_strdup(ctx, parent_fname->base_name); >- if (!*pp_dirpath) { >- return NT_STATUS_NO_MEMORY; >- } >- >- DEBUG(5,("check_parent_exists: name " >- "= %s, dirpath = %s, " >- "start = %s\n", >- smb_fname->base_name, >- *pp_dirpath, >- *pp_start)); >- >- return NT_STATUS_OK; >- >- no_optimization_out: >- >- /* >- * We must still return an *pp_dirpath >- * initialized to ".", and a *pp_start >- * pointing at smb_fname->base_name. >- */ >- >- TALLOC_FREE(parent_name); >- TALLOC_FREE(parent_fname); >- >- *pp_dirpath = talloc_strdup(ctx, "."); >- if (*pp_dirpath == NULL) { >- return NT_STATUS_NO_MEMORY; >- } >- /* >- * Safe to use discard_const_p >- * here as by convention smb_fname->base_name >- * is allocated off ctx. >- */ >- *pp_start = discard_const_p(char, smb_fname->base_name); >- return NT_STATUS_OK; >-} >- > static bool find_snapshot_token( > const char *filename, > const char **_start, >@@ -255,1138 +95,148 @@ static bool find_snapshot_token( > { > const char *start = NULL; > const char *end = NULL; >- struct tm tm; >- time_t t; >- >- start = strstr_m(filename, "@GMT-"); >- >- if (start == NULL) { >- return false; >- } >- >- if ((start > filename) && (start[-1] != '/')) { >- /* the GMT-token does not start a path-component */ >- return false; >- } >- >- end = strptime(start, GMT_FORMAT, &tm); >- if (end == NULL) { >- /* Not a valid timestring. */ >- return false; >- } >- >- if ((end[0] != '\0') && (end[0] != '/')) { >- /* >- * It is not a complete path component, i.e. the path >- * component continues after the gmt-token. >- */ >- return false; >- } >- >- tm.tm_isdst = -1; >- t = timegm(&tm); >- unix_to_nt_time(twrp, t); >- >- DBG_DEBUG("Extracted @GMT-Timestamp %s\n", >- nt_time_string(talloc_tos(), *twrp)); >- >- *_start = start; >- >- if (end[0] == '/') { >- end += 1; >- } >- *_next_component = end; >- >- return true; >-} >- >-bool extract_snapshot_token(char *fname, NTTIME *twrp) >-{ >- const char *start = NULL; >- const char *next = NULL; >- size_t remaining; >- bool found; >- >- found = find_snapshot_token(fname, &start, &next, twrp); >- if (!found) { >- return false; >- } >- >- remaining = strlen(next); >- memmove(discard_const_p(char, start), next, remaining+1); >- >- return true; >-} >- >-/* >- * Strip a valid @GMT-token from any incoming filename path, >- * adding any NTTIME encoded in the pathname into the >- * twrp field of the passed in smb_fname. >- * >- * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS >- * at the *start* of a pathname component. >- * >- * If twrp is passed in then smb_fname->twrp is set to that >- * value, and the @GMT-token part of the filename is removed >- * and does not change the stored smb_fname->twrp. >- * >- */ >- >-NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname, >- uint32_t ucf_flags, >- NTTIME twrp) >-{ >- bool found; >- >- if (twrp != 0) { >- smb_fname->twrp = twrp; >- } >- >- if (!(ucf_flags & UCF_GMT_PATHNAME)) { >- return NT_STATUS_OK; >- } >- >- found = extract_snapshot_token(smb_fname->base_name, &twrp); >- if (!found) { >- return NT_STATUS_OK; >- } >- >- if (smb_fname->twrp == 0) { >- smb_fname->twrp = twrp; >- } >- >- return NT_STATUS_OK; >-} >- >-static bool strnorm(char *s, int case_default) >-{ >- if (case_default == CASE_UPPER) >- return strupper_m(s); >- else >- return strlower_m(s); >-} >- >-/* >- * Utility function to normalize case on an incoming client filename >- * if required on this connection struct. >- * Performs an in-place case conversion guaranteed to stay the same size. >- */ >- >-static NTSTATUS normalize_filename_case(connection_struct *conn, >- char *filename, >- uint32_t ucf_flags) >-{ >- bool ok; >- >- if (ucf_flags & UCF_POSIX_PATHNAMES) { >- /* >- * POSIX never normalizes filename case. >- */ >- return NT_STATUS_OK; >- } >- if (!conn->case_sensitive) { >- return NT_STATUS_OK; >- } >- if (conn->case_preserve) { >- return NT_STATUS_OK; >- } >- if (conn->short_case_preserve) { >- return NT_STATUS_OK; >- } >- ok = strnorm(filename, lp_default_case(SNUM(conn))); >- if (!ok) { >- return NT_STATUS_INVALID_PARAMETER; >- } >- return NT_STATUS_OK; >-} >- >-/**************************************************************************** >-This routine is called to convert names from the dos namespace to unix >-namespace. It needs to handle any case conversions, mangling, format changes, >-streams etc. >- >-We assume that we have already done a chdir() to the right "root" directory >-for this service. >- >-Conversion to basic unix format is already done in check_path_syntax(). >- >-Names must be relative to the root of the service - any leading /. and >-trailing /'s should have been trimmed by check_path_syntax(). >- >-The function will return an NTSTATUS error if some part of the name except for >-the last part cannot be resolved, else NT_STATUS_OK. >- >-Note NT_STATUS_OK doesn't mean the name exists or is valid, just that we >-didn't get any fatal errors that should immediately terminate the calling SMB >-processing whilst resolving. >- >-If the orig_path was a stream, smb_filename->base_name will point to the base >-filename, and smb_filename->stream_name will point to the stream name. If >-orig_path was not a stream, then smb_filename->stream_name will be NULL. >- >-On exit from unix_convert, the smb_filename->st stat struct will be populated >-if the file exists and was found, if not this stat struct will be filled with >-zeros (and this can be detected by checking for nlinks = 0, which can never be >-true for any file). >-****************************************************************************/ >- >-struct uc_state { >- TALLOC_CTX *mem_ctx; >- struct connection_struct *conn; >- struct smb_filename *smb_fname; >- const char *orig_path; >- uint32_t ucf_flags; >- char *name; >- char *end; >- char *dirpath; >- char *stream; >- bool component_was_mangled; >- bool posix_pathnames; >- bool done; >- bool case_sensitive; >- bool case_preserve; >- bool short_case_preserve; >-}; >- >-static NTSTATUS unix_convert_step_search_fail( >- struct uc_state *state, NTSTATUS status) >-{ >- char *unmangled; >- >- if (state->end) { >- /* >- * An intermediate part of the name >- * can't be found. >- */ >- DBG_DEBUG("Intermediate [%s] missing\n", >- state->name); >- *state->end = '/'; >- >- /* >- * We need to return the fact that the >- * intermediate name resolution failed. >- * This is used to return an error of >- * ERRbadpath rather than ERRbadfile. >- * Some Windows applications depend on >- * the difference between these two >- * errors. >- */ >- >- /* >- * ENOENT, ENOTDIR and ELOOP all map >- * to NT_STATUS_OBJECT_PATH_NOT_FOUND >- * in the filename walk. >- */ >- if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) || >- NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK) || >- NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY)) { >- status = NT_STATUS_OBJECT_PATH_NOT_FOUND; >- } >- return status; >- } >- >- /* >- * ENOENT/EACCESS are the only valid errors >- * here. >- */ >- >- if (NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED)) { >- if ((state->ucf_flags & UCF_PREP_CREATEFILE) == 0) { >- /* >- * Could be a symlink pointing to >- * a directory outside the share >- * to which we don't have access. >- * If so, we need to know that here >- * so we can return the correct error code. >- * check_name() is never called if we >- * error out of filename_convert(). >- */ >- int ret; >- struct smb_filename dname = (struct smb_filename) { >- .base_name = state->dirpath, >- .twrp = state->smb_fname->twrp, >- }; >- >- /* handle null paths */ >- if ((dname.base_name == NULL) || >- (dname.base_name[0] == '\0')) { >- return NT_STATUS_ACCESS_DENIED; >- } >- ret = SMB_VFS_LSTAT(state->conn, &dname); >- if (ret != 0) { >- return NT_STATUS_ACCESS_DENIED; >- } >- if (!S_ISLNK(dname.st.st_ex_mode)) { >- return NT_STATUS_ACCESS_DENIED; >- } >- status = check_name(state->conn, &dname); >- if (!NT_STATUS_IS_OK(status)) { >- /* We know this is an intermediate path. */ >- return NT_STATUS_OBJECT_PATH_NOT_FOUND; >- } >- return NT_STATUS_ACCESS_DENIED; >- } else { >- /* >- * This is the dropbox >- * behaviour. A dropbox is a >- * directory with only -wx >- * permissions, so >- * get_real_filename fails >- * with EACCESS, it needs to >- * list the directory. We >- * nevertheless want to allow >- * users creating a file. >- */ >- status = NT_STATUS_OK; >- } >- } >- >- if (!NT_STATUS_IS_OK(status) && >- !NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { >- /* >- * ENOTDIR and ELOOP both map to >- * NT_STATUS_OBJECT_PATH_NOT_FOUND >- * in the filename walk. >- */ >- if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY) || >- NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) { >- status = NT_STATUS_OBJECT_PATH_NOT_FOUND; >- } >- return status; >- } >- >- /* >- * POSIX pathnames must never call into mangling. >- */ >- if (state->posix_pathnames) { >- goto done; >- } >- >- /* >- * Just the last part of the name doesn't exist. >- * We need to strupper() or strlower() it as >- * this conversion may be used for file creation >- * purposes. Fix inspired by >- * Thomas Neumann <t.neumann@iku-ag.de>. >- */ >- if (!state->case_preserve || >- (mangle_is_8_3(state->name, false, >- state->conn->params) && >- !state->short_case_preserve)) { >- if (!strnorm(state->name, >- lp_default_case(SNUM(state->conn)))) { >- DBG_DEBUG("strnorm %s failed\n", >- state->name); >- return NT_STATUS_INVALID_PARAMETER; >- } >- } >- >- /* >- * check on the mangled stack to see if we can >- * recover the base of the filename. >- */ >- >- if (mangle_is_mangled(state->name, state->conn->params) >- && mangle_lookup_name_from_8_3(state->mem_ctx, >- state->name, >- &unmangled, >- state->conn->params)) { >- char *tmp; >- size_t name_ofs = >- state->name - state->smb_fname->base_name; >- >- if (!ISDOT(state->dirpath)) { >- tmp = talloc_asprintf( >- state->smb_fname, "%s/%s", >- state->dirpath, unmangled); >- TALLOC_FREE(unmangled); >- } >- else { >- tmp = unmangled; >- } >- if (tmp == NULL) { >- DBG_ERR("talloc failed\n"); >- return NT_STATUS_NO_MEMORY; >- } >- TALLOC_FREE(state->smb_fname->base_name); >- state->smb_fname->base_name = tmp; >- state->name = >- state->smb_fname->base_name + name_ofs; >- state->end = state->name + strlen(state->name); >- } >- >- done: >- >- DBG_DEBUG("New file [%s]\n", state->name); >- state->done = true; >- return NT_STATUS_OK; >-} >- >-static NTSTATUS unix_convert_step_stat(struct uc_state *state) >-{ >- struct smb_filename dname; >- char dot[2] = "."; >- char *found_name = NULL; >- int ret; >- NTSTATUS status; >- >- /* >- * Check if the name exists up to this point. >- */ >- >- DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(state->smb_fname)); >- >- ret = vfs_stat(state->conn, state->smb_fname); >- if (ret == 0) { >- /* >- * It exists. it must either be a directory or this must >- * be the last part of the path for it to be OK. >- */ >- if (state->end && !S_ISDIR(state->smb_fname->st.st_ex_mode)) { >- /* >- * An intermediate part of the name isn't >- * a directory. >- */ >- DBG_DEBUG("Not a dir [%s]\n", state->name); >- *state->end = '/'; >- /* >- * We need to return the fact that the >- * intermediate name resolution failed. This >- * is used to return an error of ERRbadpath >- * rather than ERRbadfile. Some Windows >- * applications depend on the difference between >- * these two errors. >- */ >- return NT_STATUS_OBJECT_PATH_NOT_FOUND; >- } >- return NT_STATUS_OK; >- } >- >- /* Stat failed - ensure we don't use it. */ >- SET_STAT_INVALID(state->smb_fname->st); >- >- if (state->posix_pathnames) { >- /* >- * For posix_pathnames, we're done. >- * Don't blunder into the >- * get_real_filename() codepath as they may >- * be doing case insensitive lookups. So when >- * creating a new POSIX directory Foo they might >- * match on name foo. >- * >- * BUG: https://bugzilla.samba.org/show_bug.cgi?id=13803 >- */ >- if (state->end != NULL) { >- const char *morepath = NULL; >- /* >- * If this is intermediate we must >- * restore the full path. >- */ >- *state->end = '/'; >- /* >- * If there are any more components >- * after the failed LSTAT we cannot >- * continue. >- */ >- morepath = strchr(state->end + 1, '/'); >- if (morepath != NULL) { >- return NT_STATUS_OBJECT_PATH_NOT_FOUND; >- } >- } >- if (errno == ENOENT) { >- /* New file or directory. */ >- state->done = true; >- return NT_STATUS_OK; >- } >- if ((errno == EACCES) && >- (state->ucf_flags & UCF_PREP_CREATEFILE)) { >- /* POSIX Dropbox case. */ >- errno = 0; >- state->done = true; >- return NT_STATUS_OK; >- } >- return map_nt_error_from_unix(errno); >- } >- >- /* >- * Reset errno so we can detect >- * directory open errors. >- */ >- errno = 0; >- >- /* >- * Try to find this part of the path in the directory. >- */ >- >- dname = (struct smb_filename) { >- .base_name = state->dirpath, >- .twrp = state->smb_fname->twrp, >- }; >- >- /* handle null paths */ >- if ((dname.base_name == NULL) || (dname.base_name[0] == '\0')) { >- dname.base_name = dot; >- } >- >- status = get_real_filename(state->conn, >- &dname, >- state->name, >- talloc_tos(), >- &found_name); >- if (!NT_STATUS_IS_OK(status)) { >- return unix_convert_step_search_fail(state, status); >- } >- >- /* >- * Restore the rest of the string. If the string was >- * mangled the size may have changed. >- */ >- if (state->end) { >- char *tmp; >- size_t name_ofs = >- state->name - state->smb_fname->base_name; >- >- if (!ISDOT(state->dirpath)) { >- tmp = talloc_asprintf(state->smb_fname, >- "%s/%s/%s", state->dirpath, >- found_name, state->end+1); >- } >- else { >- tmp = talloc_asprintf(state->smb_fname, >- "%s/%s", found_name, >- state->end+1); >- } >- if (tmp == NULL) { >- DBG_ERR("talloc_asprintf failed\n"); >- return NT_STATUS_NO_MEMORY; >- } >- TALLOC_FREE(state->smb_fname->base_name); >- state->smb_fname->base_name = tmp; >- state->name = state->smb_fname->base_name + name_ofs; >- state->end = state->name + strlen(found_name); >- *state->end = '\0'; >- } else { >- char *tmp; >- size_t name_ofs = >- state->name - state->smb_fname->base_name; >- >- if (!ISDOT(state->dirpath)) { >- tmp = talloc_asprintf(state->smb_fname, >- "%s/%s", state->dirpath, >- found_name); >- } else { >- tmp = talloc_strdup(state->smb_fname, >- found_name); >- } >- if (tmp == NULL) { >- DBG_ERR("talloc failed\n"); >- return NT_STATUS_NO_MEMORY; >- } >- TALLOC_FREE(state->smb_fname->base_name); >- state->smb_fname->base_name = tmp; >- state->name = state->smb_fname->base_name + name_ofs; >- >- /* >- * We just scanned for, and found the end of >- * the path. We must return a valid stat struct >- * if it exists. JRA. >- */ >- >- ret = vfs_stat(state->conn, state->smb_fname); >- if (ret != 0) { >- SET_STAT_INVALID(state->smb_fname->st); >- } >- } >- >- TALLOC_FREE(found_name); >- return NT_STATUS_OK; >-} >- >-static NTSTATUS unix_convert_step(struct uc_state *state) >-{ >- NTSTATUS status; >- >- /* >- * Pinpoint the end of this section of the filename. >- */ >- /* mb safe. '/' can't be in any encoded char. */ >- state->end = strchr(state->name, '/'); >- >- /* >- * Chop the name at this point. >- */ >- if (state->end != NULL) { >- *state->end = 0; >- } >- >- DBG_DEBUG("dirpath [%s] name [%s]\n", state->dirpath, state->name); >- >- /* The name cannot have a component of "." */ >- >- if (ISDOT(state->name)) { >- if (state->end == NULL) { >- /* Error code at the end of a pathname. */ >- return NT_STATUS_OBJECT_NAME_INVALID; >- } >- return NT_STATUS_OBJECT_PATH_NOT_FOUND; >- } >- >- status = unix_convert_step_stat(state); >- if (!NT_STATUS_IS_OK(status)) { >- return status; >- } >- if (state->done) { >- return NT_STATUS_OK; >- } >- >- /* >- * Add to the dirpath that we have resolved so far. >- */ >- >- if (!ISDOT(state->dirpath)) { >- char *tmp = talloc_asprintf(state->mem_ctx, >- "%s/%s", state->dirpath, state->name); >- if (!tmp) { >- DBG_ERR("talloc_asprintf failed\n"); >- return NT_STATUS_NO_MEMORY; >- } >- TALLOC_FREE(state->dirpath); >- state->dirpath = tmp; >- } >- else { >- TALLOC_FREE(state->dirpath); >- if (!(state->dirpath = talloc_strdup(state->mem_ctx,state->name))) { >- DBG_ERR("talloc_strdup failed\n"); >- return NT_STATUS_NO_MEMORY; >- } >- } >- >- /* >- * Cache the dirpath thus far. Don't cache a name with mangled >- * components as this can change the size. >- */ >- if(!state->component_was_mangled) { >- stat_cache_add(state->orig_path, >- state->dirpath, >- state->smb_fname->twrp, >- state->case_sensitive); >- } >- >- /* >- * Restore the / that we wiped out earlier. >- */ >- if (state->end != NULL) { >- *state->end = '/'; >- } >- >- return NT_STATUS_OK; >-} >- >-NTSTATUS unix_convert(TALLOC_CTX *mem_ctx, >- connection_struct *conn, >- const char *orig_path, >- NTTIME twrp, >- struct smb_filename **smb_fname_out, >- uint32_t ucf_flags) >-{ >- struct uc_state uc_state; >- struct uc_state *state = &uc_state; >- NTSTATUS status; >- int ret = -1; >- int parent_stat_errno = 0; >- >- *state = (struct uc_state) { >- .mem_ctx = mem_ctx, >- .conn = conn, >- .orig_path = orig_path, >- .ucf_flags = ucf_flags, >- .posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES), >- .case_sensitive = conn->case_sensitive, >- .case_preserve = conn->case_preserve, >- .short_case_preserve = conn->short_case_preserve, >- }; >- >- *smb_fname_out = NULL; >- >- if (state->posix_pathnames) { >- /* POSIX means ignore case settings on share. */ >- state->case_sensitive = true; >- state->case_preserve = true; >- state->short_case_preserve = true; >- } >- >- state->smb_fname = talloc_zero(state->mem_ctx, struct smb_filename); >- if (state->smb_fname == NULL) { >- return NT_STATUS_NO_MEMORY; >- } >- >- if (state->conn->printer) { >- /* we don't ever use the filenames on a printer share as a >- filename - so don't convert them */ >- state->smb_fname->base_name = talloc_strdup( >- state->smb_fname, state->orig_path); >- if (state->smb_fname->base_name == NULL) { >- status = NT_STATUS_NO_MEMORY; >- goto err; >- } >- goto done; >- } >- >- state->smb_fname->flags = state->posix_pathnames ? SMB_FILENAME_POSIX_PATH : 0; >- >- DBG_DEBUG("Called on file [%s]\n", state->orig_path); >- >- if (state->orig_path[0] == '/') { >- DBG_ERR("Path [%s] starts with '/'\n", state->orig_path); >- return NT_STATUS_OBJECT_NAME_INVALID; >- } >- >- /* Start with the full orig_path as given by the caller. */ >- state->smb_fname->base_name = talloc_strdup( >- state->smb_fname, state->orig_path); >- if (state->smb_fname->base_name == NULL) { >- DBG_ERR("talloc_strdup failed\n"); >- status = NT_STATUS_NO_MEMORY; >- goto err; >- } >- >- /* Canonicalize any @GMT- paths. */ >- status = canonicalize_snapshot_path(state->smb_fname, ucf_flags, twrp); >- if (!NT_STATUS_IS_OK(status)) { >- goto err; >- } >- >- /* >- * If we trimmed down to a single '\0' character >- * then we should use the "." directory to avoid >- * searching the cache, but not if we are in a >- * printing share. >- * As we know this is valid we can return true here. >- */ >- >- if (state->smb_fname->base_name[0] == '\0') { >- state->smb_fname->base_name = talloc_strdup(state->smb_fname, "."); >- if (state->smb_fname->base_name == NULL) { >- status = NT_STATUS_NO_MEMORY; >- goto err; >- } >- if (SMB_VFS_STAT(state->conn, state->smb_fname) != 0) { >- status = map_nt_error_from_unix(errno); >- goto err; >- } >- DBG_DEBUG("conversion finished [] -> [%s]\n", >- state->smb_fname->base_name); >- goto done; >- } >- >- if (state->orig_path[0] == '.' && (state->orig_path[1] == '/' || >- state->orig_path[1] == '\0')) { >- /* Start of pathname can't be "." only. */ >- if (state->orig_path[1] == '\0' || state->orig_path[2] == '\0') { >- status = NT_STATUS_OBJECT_NAME_INVALID; >- } else { >- status = NT_STATUS_OBJECT_PATH_NOT_FOUND; >- } >- goto err; >- } >- >- /* >- * Large directory fix normalization. If we're case sensitive, and >- * the case preserving parameters are set to "no", normalize the case of >- * the incoming filename from the client WHETHER IT EXISTS OR NOT ! >- * This is in conflict with the current (3.0.20) man page, but is >- * what people expect from the "large directory howto". I'll update >- * the man page. Thanks to jht@samba.org for finding this. JRA. >- */ >- >- status = normalize_filename_case(state->conn, >- state->smb_fname->base_name, >- ucf_flags); >- if (!NT_STATUS_IS_OK(status)) { >- DBG_ERR("normalize_filename_case %s failed\n", >- state->smb_fname->base_name); >- goto err; >- } >- >- /* >- * Strip off the stream, and add it back when we're done with the >- * base_name. >- */ >- if (!state->posix_pathnames) { >- state->stream = strchr_m(state->smb_fname->base_name, ':'); >- >- if (state->stream != NULL) { >- char *tmp = talloc_strdup(state->smb_fname, state->stream); >- if (tmp == NULL) { >- status = NT_STATUS_NO_MEMORY; >- goto err; >- } >- /* >- * Since this is actually pointing into >- * smb_fname->base_name this truncates base_name. >- */ >- *state->stream = '\0'; >- state->stream = tmp; >- >- if (state->smb_fname->base_name[0] == '\0') { >- /* >- * orig_name was just a stream name. >- * This is a stream on the root of >- * the share. Replace base_name with >- * a "." >- */ >- state->smb_fname->base_name = >- talloc_strdup(state->smb_fname, "."); >- if (state->smb_fname->base_name == NULL) { >- status = NT_STATUS_NO_MEMORY; >- goto err; >- } >- if (SMB_VFS_STAT(state->conn, state->smb_fname) != 0) { >- status = map_nt_error_from_unix(errno); >- goto err; >- } >- /* dirpath must exist. */ >- state->dirpath = talloc_strdup(state->mem_ctx,"."); >- if (state->dirpath == NULL) { >- status = NT_STATUS_NO_MEMORY; >- goto err; >- } >- DBG_INFO("conversion finished [%s] -> [%s]\n", >- state->orig_path, >- state->smb_fname->base_name); >- goto done; >- } >- } >- } >- >- state->name = state->smb_fname->base_name; >- >- /* >- * If we're providing case insensitive semantics or >- * the underlying filesystem is case insensitive, >- * then a case-normalized hit in the stat-cache is >- * authoritative. JRA. >- * >- * Note: We're only checking base_name. The stream_name will be >- * added and verified in build_stream_path(). >- */ >- >- if (!state->case_sensitive || >- !(state->conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) >- { >- bool found; >- >- found = stat_cache_lookup(state->conn, >- &state->smb_fname->base_name, >- &state->dirpath, >- &state->name, >- state->smb_fname->twrp, >- &state->smb_fname->st); >- /* >- * stat_cache_lookup() allocates on talloc_tos() even >- * when !found, reparent correctly >- */ >- talloc_steal(state->smb_fname, state->smb_fname->base_name); >- talloc_steal(state->mem_ctx, state->dirpath); >- >- if (found) { >- goto done; >- } >- } >- >- /* >- * Make sure "dirpath" is an allocated string, we use this for >- * building the directories with talloc_asprintf and free it. >- */ >- >- if (state->dirpath == NULL) { >- state->dirpath = talloc_strdup(state->mem_ctx,"."); >- if (state->dirpath == NULL) { >- DBG_ERR("talloc_strdup failed\n"); >- status = NT_STATUS_NO_MEMORY; >- goto err; >- } >- } >- >- /* >- * If we have a wildcard we must walk the path to >- * find where the error is, even if case sensitive >- * is true. >- */ >- >- if (!state->posix_pathnames) { >- /* POSIX pathnames have no wildcards. */ >- bool name_has_wildcard = ms_has_wild(state->smb_fname->base_name); >- if (name_has_wildcard) { >- /* Wildcard not valid anywhere. */ >- status = NT_STATUS_OBJECT_NAME_INVALID; >- goto fail; >- } >- } >- >- DBG_DEBUG("Begin: name [%s] dirpath [%s] name [%s]\n", >- state->smb_fname->base_name, state->dirpath, state->name); >- >- /* >- * stat the name - if it exists then we can add the stream back (if >- * there was one) and be done! >- */ >- >- ret = vfs_stat(state->conn, state->smb_fname); >- if (ret == 0) { >- status = check_for_dot_component(state->smb_fname); >- if (!NT_STATUS_IS_OK(status)) { >- goto fail; >- } >- /* Add the path (not including the stream) to the cache. */ >- stat_cache_add(state->orig_path, >- state->smb_fname->base_name, >- state->smb_fname->twrp, >- state->case_sensitive); >- DBG_DEBUG("Conversion of base_name finished " >- "[%s] -> [%s]\n", >- state->orig_path, state->smb_fname->base_name); >- goto done; >- } >- >- /* Stat failed - ensure we don't use it. */ >- SET_STAT_INVALID(state->smb_fname->st); >- >- /* >- * Note: we must continue processing a path if we get EACCES >- * from stat. With NFS4 permissions the file might be lacking >- * READ_ATTR, but if the parent has LIST permissions we can >- * resolve the path in the path traversal loop down below. >- */ >- >- if (errno == ENOENT) { >- /* Optimization when creating a new file - only >- the last component doesn't exist. >- NOTE : check_parent_exists() doesn't preserve errno. >- */ >- int saved_errno = errno; >- status = check_parent_exists(state->mem_ctx, >- state->conn, >- state->posix_pathnames, >- state->smb_fname, >- &state->dirpath, >- &state->name, >- &parent_stat_errno); >- errno = saved_errno; >- if (!NT_STATUS_IS_OK(status)) { >- goto fail; >- } >- } >- >- /* >- * A special case - if we don't have any wildcards or mangling chars and are case >- * sensitive or the underlying filesystem is case insensitive then searching >- * won't help. >- * >- * NB. As POSIX sets state->case_sensitive as >- * true we will never call into mangle_is_mangled() here. >- */ >- >- if ((state->case_sensitive || !(state->conn->fs_capabilities & >- FILE_CASE_SENSITIVE_SEARCH)) && >- !mangle_is_mangled(state->smb_fname->base_name, state->conn->params)) { >- >- status = check_for_dot_component(state->smb_fname); >- if (!NT_STATUS_IS_OK(status)) { >- goto fail; >- } >+ struct tm tm; >+ time_t t; > >- /* >- * The stat failed. Could be ok as it could be >- * a new file. >- */ >+ start = strstr_m(filename, "@GMT-"); > >- if (errno == ENOTDIR || errno == ELOOP) { >- status = NT_STATUS_OBJECT_PATH_NOT_FOUND; >- goto fail; >- } else if (errno == ENOENT) { >- /* >- * Was it a missing last component ? >- * or a missing intermediate component ? >- * >- * Optimization. >- * >- * For this code path we can guarantee that >- * we have gone through check_parent_exists() >- * and it returned NT_STATUS_OK. >- * >- * Either there was no parent component (".") >- * parent_stat_errno == 0 and we have a missing >- * last component here. >- * >- * OR check_parent_exists() called STAT/LSTAT >- * and if it failed parent_stat_errno has been >- * set telling us if the parent existed or not. >- * >- * Either way we can avoid another STAT/LSTAT >- * system call on the parent here. >- */ >- if (parent_stat_errno == ENOTDIR || >- parent_stat_errno == ENOENT || >- parent_stat_errno == ELOOP) { >- status = NT_STATUS_OBJECT_PATH_NOT_FOUND; >- goto fail; >- } >+ if (start == NULL) { >+ return false; >+ } > >- /* >- * Missing last component is ok - new file. >- * Also deal with permission denied elsewhere. >- * Just drop out to done. >- */ >- goto done; >- } >+ if ((start > filename) && (start[-1] != '/')) { >+ /* the GMT-token does not start a path-component */ >+ return false; > } > >- /* >- * is_mangled() was changed to look at an entire pathname, not >- * just a component. JRA. >- */ >+ end = strptime(start, GMT_FORMAT, &tm); >+ if (end == NULL) { >+ /* Not a valid timestring. */ >+ return false; >+ } > >- if (state->posix_pathnames) { >+ if ((end[0] != '\0') && (end[0] != '/')) { > /* >- * POSIX names are never mangled and we must not >- * call into mangling functions. >+ * It is not a complete path component, i.e. the path >+ * component continues after the gmt-token. > */ >- state->component_was_mangled = false; >- } else if (mangle_is_mangled(state->name, state->conn->params)) { >- state->component_was_mangled = true; >+ return false; > } > >- /* >- * Now we need to recursively match the name against the real >- * directory structure. >- */ >+ tm.tm_isdst = -1; >+ t = timegm(&tm); >+ unix_to_nt_time(twrp, t); > >- /* >- * Match each part of the path name separately, trying the names >- * as is first, then trying to scan the directory for matching names. >- */ >+ DBG_DEBUG("Extracted @GMT-Timestamp %s\n", >+ nt_time_string(talloc_tos(), *twrp)); > >- for (; state->name ; state->name = (state->end ? state->end + 1:(char *)NULL)) { >- status = unix_convert_step(state); >- if (!NT_STATUS_IS_OK(status)) { >- if (NT_STATUS_EQUAL(status, NT_STATUS_NO_MEMORY)) { >- goto err; >- } >- goto fail; >- } >- if (state->done) { >- goto done; >- } >+ *_start = start; >+ >+ if (end[0] == '/') { >+ end += 1; > } >+ *_next_component = end; > >- /* >- * Cache the full path. Don't cache a name with mangled or wildcard >- * components as this can change the size. >- */ >+ return true; >+} >+ >+bool extract_snapshot_token(char *fname, NTTIME *twrp) >+{ >+ const char *start = NULL; >+ const char *next = NULL; >+ size_t remaining; >+ bool found; > >- if(!state->component_was_mangled) { >- stat_cache_add(state->orig_path, >- state->smb_fname->base_name, >- state->smb_fname->twrp, >- state->case_sensitive); >+ found = find_snapshot_token(fname, &start, &next, twrp); >+ if (!found) { >+ return false; > } > >- /* >- * The name has been resolved. >- */ >+ remaining = strlen(next); >+ memmove(discard_const_p(char, start), next, remaining+1); > >- done: >- /* Add back the stream if one was stripped off originally. */ >- if (state->stream != NULL) { >- state->smb_fname->stream_name = state->stream; >+ return true; >+} > >- /* Check path now that the base_name has been converted. */ >- status = build_stream_path(state->mem_ctx, state->conn, state->smb_fname); >- if (!NT_STATUS_IS_OK(status)) { >- goto fail; >- } >+/* >+ * Strip a valid @GMT-token from any incoming filename path, >+ * adding any NTTIME encoded in the pathname into the >+ * twrp field of the passed in smb_fname. >+ * >+ * Valid @GMT-tokens look like @GMT-YYYY-MM-DD-HH-MM-SS >+ * at the *start* of a pathname component. >+ * >+ * If twrp is passed in then smb_fname->twrp is set to that >+ * value, and the @GMT-token part of the filename is removed >+ * and does not change the stored smb_fname->twrp. >+ * >+ */ >+ >+NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname, >+ uint32_t ucf_flags, >+ NTTIME twrp) >+{ >+ bool found; >+ >+ if (twrp != 0) { >+ smb_fname->twrp = twrp; > } > >- DBG_DEBUG("Conversion finished [%s] -> [%s]\n", >- state->orig_path, smb_fname_str_dbg(state->smb_fname)); >+ if (!(ucf_flags & UCF_GMT_PATHNAME)) { >+ return NT_STATUS_OK; >+ } > >- TALLOC_FREE(state->dirpath); >- *smb_fname_out = state->smb_fname; >- return NT_STATUS_OK; >- fail: >- DBG_DEBUG("Conversion failed: dirpath [%s] name [%s]\n", >- state->dirpath, state->name); >- if ((state->dirpath != NULL) && !ISDOT(state->dirpath)) { >- state->smb_fname->base_name = talloc_asprintf( >- state->smb_fname, >- "%s/%s", >- state->dirpath, >- state->name); >- } else { >- state->smb_fname->base_name = talloc_strdup( >- state->smb_fname, state->name); >+ found = extract_snapshot_token(smb_fname->base_name, &twrp); >+ if (!found) { >+ return NT_STATUS_OK; > } >- if (state->smb_fname->base_name == NULL) { >- DBG_ERR("talloc_asprintf failed\n"); >- status = NT_STATUS_NO_MEMORY; >- goto err; >+ >+ if (smb_fname->twrp == 0) { >+ smb_fname->twrp = twrp; > } > >- *smb_fname_out = state->smb_fname; >- TALLOC_FREE(state->dirpath); >- return status; >- err: >- TALLOC_FREE(state->smb_fname); >- return status; >+ return NT_STATUS_OK; > } > >-/**************************************************************************** >- Ensure a path is not vetoed. >-****************************************************************************/ >- >-static NTSTATUS check_veto_path(connection_struct *conn, >- const struct smb_filename *smb_fname) >+static bool strnorm(char *s, int case_default) > { >- const char *name = smb_fname->base_name; >- >- if (IS_VETO_PATH(conn, name)) { >- /* Is it not dot or dot dot. */ >- if (!(ISDOT(name) || ISDOTDOT(name))) { >- DEBUG(5,("check_veto_path: file path name %s vetoed\n", >- name)); >- return map_nt_error_from_unix(ENOENT); >- } >- } >- return NT_STATUS_OK; >+ if (case_default == CASE_UPPER) >+ return strupper_m(s); >+ else >+ return strlower_m(s); > } > >-/**************************************************************************** >- Check a filename - possibly calling check_reduced_name. >- This is called by every routine before it allows an operation on a filename. >- It does any final confirmation necessary to ensure that the filename is >- a valid one for the user to access. >-****************************************************************************/ >+/* >+ * Utility function to normalize case on an incoming client filename >+ * if required on this connection struct. >+ * Performs an in-place case conversion guaranteed to stay the same size. >+ */ > >-static NTSTATUS check_name(connection_struct *conn, >- const struct smb_filename *smb_fname) >+static NTSTATUS normalize_filename_case(connection_struct *conn, >+ char *filename, >+ uint32_t ucf_flags) > { >- NTSTATUS status = check_veto_path(conn, smb_fname); >+ bool ok; > >- if (!NT_STATUS_IS_OK(status)) { >- return status; >+ if (ucf_flags & UCF_POSIX_PATHNAMES) { >+ /* >+ * POSIX never normalizes filename case. >+ */ >+ return NT_STATUS_OK; > } >- >- if (!lp_widelinks(SNUM(conn)) || !lp_follow_symlinks(SNUM(conn))) { >- status = check_reduced_name(conn, NULL, smb_fname); >- if (!NT_STATUS_IS_OK(status)) { >- DEBUG(5,("check_name: name %s failed with %s\n", >- smb_fname->base_name, >- nt_errstr(status))); >- return status; >- } >+ if (!conn->case_sensitive) { >+ return NT_STATUS_OK; >+ } >+ if (conn->case_preserve) { >+ return NT_STATUS_OK; >+ } >+ if (conn->short_case_preserve) { >+ return NT_STATUS_OK; >+ } >+ ok = strnorm(filename, lp_default_case(SNUM(conn))); >+ if (!ok) { >+ return NT_STATUS_INVALID_PARAMETER; > } >- > return NT_STATUS_OK; > } > >@@ -1580,41 +430,6 @@ NTSTATUS get_real_filename_full_scan_at(struct files_struct *dirfsp, > return NT_STATUS_OBJECT_NAME_NOT_FOUND; > } > >-NTSTATUS get_real_filename_full_scan(connection_struct *conn, >- const char *path, >- const char *name, >- bool mangled, >- TALLOC_CTX *mem_ctx, >- char **found_name) >-{ >- struct smb_filename *smb_dname = NULL; >- NTSTATUS status; >- >- /* handle null paths */ >- if ((path == NULL) || (*path == 0)) { >- path = "."; >- } >- >- status = synthetic_pathref( >- talloc_tos(), >- conn->cwd_fsp, >- path, >- NULL, >- NULL, >- 0, >- 0, >- &smb_dname); >- if (!NT_STATUS_IS_OK(status)) { >- return status; >- } >- >- status = get_real_filename_full_scan_at( >- smb_dname->fsp, name, mangled, mem_ctx, found_name); >- >- TALLOC_FREE(smb_dname); >- return status; >-} >- > /**************************************************************************** > Wrapper around the vfs get_real_filename and the full directory scan > fallback. >@@ -1703,172 +518,6 @@ static bool get_real_filename_cache_key( > return true; > } > >-static NTSTATUS get_real_filename(connection_struct *conn, >- struct smb_filename *path, >- const char *name, >- TALLOC_CTX *mem_ctx, >- char **found_name) >-{ >- struct smb_filename *smb_dname = NULL; >- NTSTATUS status; >- >- smb_dname = cp_smb_filename_nostream(talloc_tos(), path); >- if (smb_dname == NULL) { >- return NT_STATUS_NO_MEMORY; >- } >- >-again: >- status = openat_pathref_fsp(conn->cwd_fsp, smb_dname); >- >- if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) && >- S_ISLNK(smb_dname->st.st_ex_mode)) { >- status = NT_STATUS_STOPPED_ON_SYMLINK; >- } >- >- if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND) && >- (smb_dname->twrp != 0)) { >- /* >- * Retry looking at the non-snapshot path, copying the >- * fallback mechanism from vfs_shadow_copy2.c when >- * shadow_copy2_convert() fails. This path-based >- * routine get_real_filename() should go away and be >- * replaced with a fd-based one, so spoiling it with a >- * shadow_copy2 specific mechanism should not be too >- * bad. >- */ >- smb_dname->twrp = 0; >- goto again; >- } >- >- if (!NT_STATUS_IS_OK(status)) { >- DBG_DEBUG("openat_pathref_fsp(%s) failed: %s\n", >- smb_fname_str_dbg(smb_dname), >- nt_errstr(status)); >- >- /* >- * ENOTDIR and ELOOP both map to >- * NT_STATUS_OBJECT_PATH_NOT_FOUND in the filename >- * walk. >- */ >- if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_A_DIRECTORY) || >- NT_STATUS_EQUAL(status, NT_STATUS_STOPPED_ON_SYMLINK)) { >- status = NT_STATUS_OBJECT_PATH_NOT_FOUND; >- } >- >- return status; >- } >- >- status = get_real_filename_at( >- smb_dname->fsp, name, mem_ctx, found_name); >- TALLOC_FREE(smb_dname); >- return status; >-} >- >-static NTSTATUS build_stream_path(TALLOC_CTX *mem_ctx, >- connection_struct *conn, >- struct smb_filename *smb_fname) >-{ >- NTSTATUS status; >- unsigned int i, num_streams = 0; >- struct stream_struct *streams = NULL; >- struct smb_filename *pathref = NULL; >- >- if (SMB_VFS_STAT(conn, smb_fname) == 0) { >- DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname))); >- return NT_STATUS_OK; >- } >- >- if (errno != ENOENT) { >- DEBUG(10, ("vfs_stat failed: %s\n", strerror(errno))); >- status = map_nt_error_from_unix(errno); >- goto fail; >- } >- >- if (smb_fname->fsp == NULL) { >- status = synthetic_pathref(mem_ctx, >- conn->cwd_fsp, >- smb_fname->base_name, >- NULL, >- NULL, >- smb_fname->twrp, >- smb_fname->flags, >- &pathref); >- if (!NT_STATUS_IS_OK(status)) { >- if (NT_STATUS_EQUAL(status, >- NT_STATUS_OBJECT_NAME_NOT_FOUND)) { >- TALLOC_FREE(pathref); >- SET_STAT_INVALID(smb_fname->st); >- return NT_STATUS_OK; >- } >- DBG_DEBUG("synthetic_pathref failed: %s\n", >- nt_errstr(status)); >- goto fail; >- } >- } else { >- pathref = smb_fname; >- } >- >- /* Fall back to a case-insensitive scan of all streams on the file. */ >- status = vfs_fstreaminfo(pathref->fsp, mem_ctx, >- &num_streams, &streams); >- if (NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) { >- SET_STAT_INVALID(smb_fname->st); >- TALLOC_FREE(pathref); >- return NT_STATUS_OK; >- } >- >- if (!NT_STATUS_IS_OK(status)) { >- DEBUG(10, ("vfs_fstreaminfo failed: %s\n", nt_errstr(status))); >- goto fail; >- } >- >- for (i=0; i<num_streams; i++) { >- bool equal = sname_equal( >- smb_fname->stream_name, >- streams[i].name, >- conn->case_sensitive); >- >- DBG_DEBUG("comparing [%s] and [%s]: %sequal\n", >- smb_fname->stream_name, >- streams[i].name, >- equal ? "" : "not "); >- >- if (equal) { >- break; >- } >- } >- >- /* Couldn't find the stream. */ >- if (i == num_streams) { >- SET_STAT_INVALID(smb_fname->st); >- TALLOC_FREE(pathref); >- TALLOC_FREE(streams); >- return NT_STATUS_OK; >- } >- >- DEBUG(10, ("case insensitive stream. requested: %s, actual: %s\n", >- smb_fname->stream_name, streams[i].name)); >- >- >- TALLOC_FREE(smb_fname->stream_name); >- smb_fname->stream_name = talloc_strdup(smb_fname, streams[i].name); >- if (smb_fname->stream_name == NULL) { >- status = NT_STATUS_NO_MEMORY; >- goto fail; >- } >- >- SET_STAT_INVALID(smb_fname->st); >- >- if (SMB_VFS_STAT(conn, smb_fname) == 0) { >- DEBUG(10, ("'%s' exists\n", smb_fname_str_dbg(smb_fname))); >- } >- status = NT_STATUS_OK; >- fail: >- TALLOC_FREE(pathref); >- TALLOC_FREE(streams); >- return status; >-} >- > /* > * Lightweight function to just get last component > * for rename / enumerate directory calls. >diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h >index bc305bce296..5ac0f713958 100644 >--- a/source3/smbd/proto.h >+++ b/source3/smbd/proto.h >@@ -350,22 +350,10 @@ NTSTATUS sync_file(connection_struct *conn, files_struct *fsp, bool write_throug > > uint32_t ucf_flags_from_smb_request(struct smb_request *req); > uint32_t filename_create_ucf_flags(struct smb_request *req, uint32_t create_disposition); >-NTSTATUS unix_convert(TALLOC_CTX *ctx, >- connection_struct *conn, >- const char *orig_path, >- NTTIME twrp, >- struct smb_filename **smb_fname, >- uint32_t ucf_flags); > bool extract_snapshot_token(char *fname, NTTIME *twrp); > NTSTATUS canonicalize_snapshot_path(struct smb_filename *smb_fname, > uint32_t ucf_flags, > NTTIME twrp); >-NTSTATUS get_real_filename_full_scan(connection_struct *conn, >- const char *path, >- const char *name, >- bool mangled, >- TALLOC_CTX *mem_ctx, >- char **found_name); > NTSTATUS get_real_filename_full_scan_at(struct files_struct *dirfsp, > const char *name, > bool mangled, >-- >2.34.1 >
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Raw
Flags:
slow
:
review+
Actions:
View
Attachments on
bug 15144
: 17473