[SCM] Samba Shared Repository - branch master updated

Jeremy Allison jra at samba.org
Fri Apr 24 23:22:02 UTC 2020


The branch, master has been updated
       via  e7dfe87ac64 smbd: unix_convert_step(). Fix use of state->end as a boolean, always compare with NULL.
       via  90713cbd632 smbd: add some logging to unix_convert()
       via  e8fc1965131 smbd: factor out unix_convert_step_search_fail()
       via  a5b0271e0c3 smbd: use an early exit if stat succeeds in unix_convert_step_stat()
       via  a2f45282901 smbd: factor out unix_convert_step_stat() from unix_convert_step()
       via  beb8ff55390 smbd: remove goto from unix_convert_step()
       via  b9d61a23bda smbd: factor out path loop in unix_convert()
       via  ec2adb43481 smbd: use a different error out in one place in unix_convert()
       via  10eadd60735 smbd: in unix_convert() replace all local variable with a state struct
       via  67e1e8184a9 smbd: rename ctx variable to mem_ctx in unix_convert()
       via  025e45726e3 smbd: change variable name start to name in unix_convert()
      from  4524daafb89 lib: Fix a valgrind error

https://git.samba.org/?p=samba.git;a=shortlog;h=master


- Log -----------------------------------------------------------------
commit e7dfe87ac64f5867e587e9f252cf0d6f41f01c63
Author: Jeremy Allison <jra at samba.org>
Date:   Fri Apr 24 13:55:49 2020 -0700

    smbd: unix_convert_step(). Fix use of state->end as a boolean, always compare with NULL.
    
    Signed-off-by: Jeremy Allison <jra at samba.org>
    Reviewed-by: Ralph Boehme <slow at samba.org>
    
    Autobuild-User(master): Jeremy Allison <jra at samba.org>
    Autobuild-Date(master): Fri Apr 24 23:21:16 UTC 2020 on sn-devel-184

commit 90713cbd6323f1844c1e405460436226a47e0daf
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Apr 23 16:09:28 2020 +0200

    smbd: add some logging to unix_convert()
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit e8fc196513151f373c640432e52edb4e27bd8789
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Apr 23 12:35:12 2020 +0200

    smbd: factor out unix_convert_step_search_fail()
    
    Again, just moving code from unix_convert_step_stat() without any logic changes.
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit a5b0271e0c3d4354f0e7dfc3eb149607e7cc118f
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Apr 23 11:46:19 2020 +0200

    smbd: use an early exit if stat succeeds in unix_convert_step_stat()
    
    Allows decreasing the indentation level of the bulk of the code that handles
    stat failure. Best viewed with `git show -w`.
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit a2f452829014928dfefc8e88e72eae6f6295ead7
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Apr 23 11:40:25 2020 +0200

    smbd: factor out unix_convert_step_stat() from unix_convert_step()
    
    The diff looks more complicated that it is: everything in the new
    unix_convert_step_stat() is moved *as is* from unix_convert_step() without
    further changes.
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit beb8ff5539092d83bcaf22f612528e39d0509960
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Apr 23 12:18:29 2020 +0200

    smbd: remove goto from unix_convert_step()
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit b9d61a23bda4e718fb6b65e06dfdcb7ce2c28a9d
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Apr 23 11:16:36 2020 +0200

    smbd: factor out path loop in unix_convert()
    
    Just a copy&paste of everything in the for loop without any changes other then
    removing one indentation level. Even keeping the gotos, removing them comes in
    the next commit.
    
    No change in behaviuour.
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit ec2adb43481175566627a1676aaf0639fd550057
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Apr 23 12:00:38 2020 +0200

    smbd: use a different error out in one place in unix_convert()
    
    The error label is only used for OOM conditions no smb_fname of dirpath.
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 10eadd6073555f85cd3cd9da79c3c37842de8ccb
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Apr 23 10:06:56 2020 +0200

    smbd: in unix_convert() replace all local variable with a state struct
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 67e1e8184a980cac50cd3f51bc5ee2e137f04336
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Apr 23 09:39:22 2020 +0200

    smbd: rename ctx variable to mem_ctx in unix_convert()
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

commit 025e45726e330e4cf43f50aa230fbc65513d068e
Author: Ralph Boehme <slow at samba.org>
Date:   Thu Apr 23 09:32:53 2020 +0200

    smbd: change variable name start to name in unix_convert()
    
    start always points at the current single component name in the path traversal
    loop.
    
    Signed-off-by: Ralph Boehme <slow at samba.org>
    Reviewed-by: Jeremy Allison <jra at samba.org>

-----------------------------------------------------------------------

Summary of changes:
 source3/smbd/filename.c | 1043 ++++++++++++++++++++++++-----------------------
 1 file changed, 542 insertions(+), 501 deletions(-)


Changeset truncated at 500 lines:

diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c
index 1bf09053bbc..f45a45c8c7f 100644
--- a/source3/smbd/filename.c
+++ b/source3/smbd/filename.c
@@ -458,50 +458,476 @@ zeros (and this can be detected by checking for nlinks = 0, which can never be
 true for any file).
 ****************************************************************************/
 
-NTSTATUS unix_convert(TALLOC_CTX *ctx,
+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 name_has_wildcard;
+	bool posix_pathnames;
+	bool allow_wcard_last_component;
+	bool snapshot_path;
+	bool done;
+};
+
+static NTSTATUS unix_convert_step_search_fail(struct uc_state *state)
+{
+	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 (errno == ENOENT ||
+		    errno == ENOTDIR ||
+		    errno == ELOOP)
+		{
+			return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+		}
+		return map_nt_error_from_unix(errno);
+	}
+
+	/*
+	 * ENOENT/EACCESS are the only valid errors
+	 * here.
+	 */
+
+	if (errno == EACCES) {
+		if ((state->ucf_flags & UCF_PREP_CREATEFILE) == 0) {
+			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.
+			 */
+			errno = 0;
+		}
+	}
+
+	if ((errno != 0) && (errno != ENOENT)) {
+		/*
+		 * ENOTDIR and ELOOP both map to
+		 * NT_STATUS_OBJECT_PATH_NOT_FOUND
+		 * in the filename walk.
+		 */
+		if (errno == ENOTDIR || errno == ELOOP) {
+			return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+		}
+		return map_nt_error_from_unix(errno);
+	}
+
+	/*
+	 * 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 at iku-ag.de>.
+	 */
+	if (!state->conn->case_preserve ||
+	    (mangle_is_8_3(state->name, false,
+			   state->conn->params) &&
+	     !state->conn->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);
+	}
+
+	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)
+{
+	char *found_name = NULL;
+	int ret;
+
+	/*
+	 * Check if the name exists up to this point.
+	 */
+
+	DBG_DEBUG("smb_fname [%s]\n", smb_fname_str_dbg(state->smb_fname));
+
+	if (state->posix_pathnames) {
+		ret = SMB_VFS_LSTAT(state->conn, state->smb_fname);
+	} else {
+		ret = SMB_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 name_has_wildcard OR
+		 * get_real_filename() codepaths 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.
+	 */
+
+	if (state->name_has_wildcard) {
+		return unix_convert_step_search_fail(state);
+	}
+	ret = get_real_filename(state->conn,
+				state->dirpath,
+				state->name,
+				talloc_tos(),
+				&found_name);
+	if (ret != 0) {
+		return unix_convert_step_search_fail(state);
+	}
+
+	/*
+	 * 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.
+		 */
+
+		if (state->posix_pathnames) {
+			ret = SMB_VFS_LSTAT(state->conn, state->smb_fname);
+		} else {
+			ret = SMB_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 determine_path_error(state->end+1,
+					    state->allow_wcard_last_component,
+					    state->posix_pathnames);
+	}
+
+	/* The name cannot have a wildcard if it's not
+	   the last component. */
+
+	if (!state->posix_pathnames) {
+		state->name_has_wildcard = ms_has_wild(state->name);
+	}
+
+	/* Wildcards never valid within a pathname. */
+	if (state->name_has_wildcard && state->end != NULL) {
+		return NT_STATUS_OBJECT_NAME_INVALID;
+	}
+
+	/* Skip the stat call if it's a wildcard end. */
+	if (state->name_has_wildcard) {
+		DBG_DEBUG("Wildcard [%s]\n", state->name);
+		state->done = true;
+		return NT_STATUS_OK;
+	}
+
+	status = unix_convert_step_stat(state);
+	if (!NT_STATUS_IS_OK(status)) {
+		return status;
+	}
+
+	/*
+	 * 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
+	 * or wildcard components as this can change the size.
+	 */
+	if(!state->component_was_mangled && !state->name_has_wildcard) {
+		stat_cache_add(state->orig_path, state->dirpath,
+			       state->conn->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,
 		      struct smb_filename **smb_fname_out,
 		      uint32_t ucf_flags)
 {
-	struct smb_filename *smb_fname = NULL;
-	char *start = NULL;
-	char *end = NULL;
-	char *dirpath = NULL;
-	char *stream = NULL;
-	bool component_was_mangled = false;
-	bool name_has_wildcard = false;
-	bool posix_pathnames = (ucf_flags & UCF_POSIX_PATHNAMES);
-	bool allow_wcard_last_component =
-	    (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP);
-	bool snapshot_path = (ucf_flags & UCF_GMT_PATHNAME);
+	struct uc_state uc_state;
+	struct uc_state *state = &uc_state;
 	NTSTATUS status;
 	int ret = -1;
 
+	*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),
+		.allow_wcard_last_component = (ucf_flags & UCF_ALWAYS_ALLOW_WCARD_LCOMP),
+		.snapshot_path = (ucf_flags & UCF_GMT_PATHNAME),
+	};
+
 	*smb_fname_out = NULL;
 
-	smb_fname = talloc_zero(ctx, struct smb_filename);
-	if (smb_fname == NULL) {
+	state->smb_fname = talloc_zero(state->mem_ctx, struct smb_filename);
+	if (state->smb_fname == NULL) {
 		return NT_STATUS_NO_MEMORY;
 	}
 
-	if (conn->printer) {
+	if (state->conn->printer) {
 		/* we don't ever use the filenames on a printer share as a
 			filename - so don't convert them */
-		if (!(smb_fname->base_name = talloc_strdup(smb_fname,
-							   orig_path))) {
+		if (!(state->smb_fname->base_name = talloc_strdup(state->smb_fname,
+							   state->orig_path))) {
 			status = NT_STATUS_NO_MEMORY;
 			goto err;
 		}
 		goto done;
 	}
 
-	smb_fname->flags = posix_pathnames ? SMB_FILENAME_POSIX_PATH : 0;
+	state->smb_fname->flags = state->posix_pathnames ? SMB_FILENAME_POSIX_PATH : 0;
 
-	DBG_DEBUG("Called on file [%s]\n", orig_path);
+	DBG_DEBUG("Called on file [%s]\n", state->orig_path);
 
-	if (orig_path[0] == '/') {
-		DBG_ERR("Path [%s] starts with '/'\n", orig_path);
+	if (state->orig_path[0] == '/') {
+		DBG_ERR("Path [%s] starts with '/'\n", state->orig_path);
 		return NT_STATUS_OBJECT_NAME_INVALID;


-- 
Samba Shared Repository



More information about the samba-cvs mailing list