From b211d8a56d1beab8d570bbe28ff00beafeeaf93a Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Mon, 25 Jul 2011 16:12:45 -0700 Subject: [PATCH 1/4] Use existing ISDOT and ISDOTDOT macros. Autobuild-User: Jeremy Allison Autobuild-Date: Thu Jul 28 02:09:20 CEST 2011 on sn-devel-104 (cherry picked from commit d82256ca119eb8315cc69ba725ba71c386caa901) --- source3/smbd/filename.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 25301e6..34bb7f5 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -987,8 +987,7 @@ NTSTATUS check_name(connection_struct *conn, const char *name) { if (IS_VETO_PATH(conn, name)) { /* Is it not dot or dot dot. */ - if (!((name[0] == '.') && (!name[1] || - (name[1] == '.' && !name[2])))) { + if (!(ISDOT(name) || ISDOTDOT(name))) { DEBUG(5,("check_name: file path name %s vetoed\n", name)); return map_nt_error_from_unix(ENOENT); -- 1.7.3.1 From bb5c174a471dcc3b3d68b09bf20b82c4547aa58d Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 21 Oct 2011 14:12:41 -0700 Subject: [PATCH 2/4] Fix bug #8541 - readlink() on Linux clients fails if the symlink target is outside of the share. The key is to only allow the lookup to succeed if it's a UNIX level lookup or readlink, but disallow all other operations. (cherry picked from commit d2ec9d20858b8e5256bf8339395c6f47793e0975) --- source3/include/smb.h | 1 + source3/smbd/filename.c | 34 +++++++++++++++++++++++++++------- source3/smbd/proto.h | 1 + source3/smbd/trans2.c | 18 ++++++++++++++---- 4 files changed, 43 insertions(+), 11 deletions(-) diff --git a/source3/include/smb.h b/source3/include/smb.h index 3a64af7..549ebb2 100644 --- a/source3/include/smb.h +++ b/source3/include/smb.h @@ -1714,6 +1714,7 @@ struct smb_file_time { #define UCF_ALWAYS_ALLOW_WCARD_LCOMP 0x00000002 #define UCF_COND_ALLOW_WCARD_LCOMP 0x00000004 #define UCF_POSIX_PATHNAMES 0x00000008 +#define UCF_UNIX_NAME_LOOKUP 0x00000010 /* * smb_filename diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 34bb7f5..691a779 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -977,25 +977,39 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, } /**************************************************************************** - 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. + Ensure a path is not vetod. ****************************************************************************/ -NTSTATUS check_name(connection_struct *conn, const char *name) +NTSTATUS check_veto_path(connection_struct *conn, const char *name) { if (IS_VETO_PATH(conn, name)) { /* Is it not dot or dot dot. */ if (!(ISDOT(name) || ISDOTDOT(name))) { - DEBUG(5,("check_name: file path name %s vetoed\n", + DEBUG(5,("check_veto_path: file path name %s vetoed\n", name)); return map_nt_error_from_unix(ENOENT); } } + return NT_STATUS_OK; +} + +/**************************************************************************** + 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. +****************************************************************************/ + +NTSTATUS check_name(connection_struct *conn, const char *name) +{ + NTSTATUS status = check_veto_path(conn, name); + + if (!NT_STATUS_IS_OK(status)) { + return status; + } if (!lp_widelinks(SNUM(conn)) || !lp_symlinks(SNUM(conn))) { - NTSTATUS status = check_reduced_name(conn,name); + status = check_reduced_name(conn,name); if (!NT_STATUS_IS_OK(status)) { DEBUG(5,("check_name: name %s failed with %s\n",name, nt_errstr(status))); @@ -1313,6 +1327,12 @@ NTSTATUS filename_convert(TALLOC_CTX *ctx, return status; } + if ((ucf_flags & UCF_UNIX_NAME_LOOKUP) && + VALID_STAT((*pp_smb_fname)->st) && + S_ISLNK((*pp_smb_fname)->st.st_ex_mode)) { + return check_veto_path(conn, (*pp_smb_fname)->base_name); + } + status = check_name(conn, (*pp_smb_fname)->base_name); if (!NT_STATUS_IS_OK(status)) { DEBUG(3,("filename_convert: check_name failed " diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index c455ffe..1e5d891 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -336,6 +336,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, const char *orig_path, struct smb_filename **smb_fname, uint32_t ucf_flags); +NTSTATUS check_veto_path(connection_struct *conn, const char *name); NTSTATUS check_name(connection_struct *conn, const char *name); int get_real_filename(connection_struct *conn, const char *path, const char *name, TALLOC_CTX *mem_ctx, diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 0931fff..284635d 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -2271,6 +2271,7 @@ static void call_trans2findfirst(connection_struct *conn, TALLOC_CTX *ctx = talloc_tos(); struct dptr_struct *dirptr = NULL; struct smbd_server_connection *sconn = req->sconn; + uint32_t ucf_flags = (UCF_SAVE_LCOMP | UCF_ALWAYS_ALLOW_WCARD_LCOMP); if (total_params < 13) { reply_nterror(req, NT_STATUS_INVALID_PARAMETER); @@ -2314,6 +2315,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", reply_nterror(req, NT_STATUS_INVALID_LEVEL); goto out; } + ucf_flags |= UCF_UNIX_NAME_LOOKUP; break; default: reply_nterror(req, NT_STATUS_INVALID_LEVEL); @@ -5103,6 +5105,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, } else { uint32_t name_hash; char *fname = NULL; + uint32_t ucf_flags = 0; /* qpathinfo */ if (total_params < 7) { @@ -5114,9 +5117,16 @@ static void call_trans2qfilepathinfo(connection_struct *conn, DEBUG(3,("call_trans2qfilepathinfo: TRANSACT2_QPATHINFO: level = %d\n", info_level)); - if (INFO_LEVEL_IS_UNIX(info_level) && !lp_unix_extensions()) { - reply_nterror(req, NT_STATUS_INVALID_LEVEL); - return; + if (INFO_LEVEL_IS_UNIX(info_level)) { + if (!lp_unix_extensions()) { + reply_nterror(req, NT_STATUS_INVALID_LEVEL); + return; + } + if (info_level == SMB_QUERY_FILE_UNIX_BASIC || + info_level == SMB_QUERY_FILE_UNIX_INFO2 || + info_level == SMB_QUERY_FILE_UNIX_LINK) { + ucf_flags |= UCF_UNIX_NAME_LOOKUP; + } } srvstr_get_path(req, params, req->flags2, &fname, ¶ms[6], @@ -5131,7 +5141,7 @@ static void call_trans2qfilepathinfo(connection_struct *conn, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, fname, - 0, + ucf_flags, NULL, &smb_fname); if (!NT_STATUS_IS_OK(status)) { -- 1.7.3.1 From fe96a8513b5544db27e106bf29aa744c464d843b Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 21 Oct 2011 17:46:12 -0700 Subject: [PATCH 3/4] Second part of fix for bug #8541 - readlink() on Linux clients fails if the symlink target is outside of the share. The statcache has to do lstat instead of stat when returning cached posix pathnames. (cherry picked from commit 305d7d7f7d76e37d82ce6ac257f178ce654b26db) --- source3/smbd/filename.c | 2 +- source3/smbd/proto.h | 1 + source3/smbd/statcache.c | 11 ++++++++++- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/source3/smbd/filename.c b/source3/smbd/filename.c index 691a779..b2ed239 100644 --- a/source3/smbd/filename.c +++ b/source3/smbd/filename.c @@ -383,7 +383,7 @@ NTSTATUS unix_convert(TALLOC_CTX *ctx, if((!conn->case_sensitive || !(conn->fs_capabilities & FILE_CASE_SENSITIVE_SEARCH)) && - stat_cache_lookup(conn, &smb_fname->base_name, &dirpath, &start, + stat_cache_lookup(conn, posix_pathnames, &smb_fname->base_name, &dirpath, &start, &smb_fname->st)) { goto done; } diff --git a/source3/smbd/proto.h b/source3/smbd/proto.h index 1e5d891..02b5e40 100644 --- a/source3/smbd/proto.h +++ b/source3/smbd/proto.h @@ -1038,6 +1038,7 @@ void stat_cache_add( const char *full_orig_name, char *translated_path, bool case_sensitive); bool stat_cache_lookup(connection_struct *conn, + bool posix_paths, char **pp_name, char **pp_dirpath, char **pp_start, diff --git a/source3/smbd/statcache.c b/source3/smbd/statcache.c index e2ccc74..e910982 100644 --- a/source3/smbd/statcache.c +++ b/source3/smbd/statcache.c @@ -150,6 +150,7 @@ void stat_cache_add( const char *full_orig_name, * Look through the stat cache for an entry * * @param conn A connection struct to do the stat() with. + * @param posix_paths Whether to lookup using stat() or lstat() * @param name The path we are attempting to cache, modified by this routine * to be correct as far as the cache can tell us. We assume that * it is a talloc'ed string from top of stack, we free it if @@ -166,6 +167,7 @@ void stat_cache_add( const char *full_orig_name, */ bool stat_cache_lookup(connection_struct *conn, + bool posix_paths, char **pp_name, char **pp_dirpath, char **pp_start, @@ -181,6 +183,7 @@ bool stat_cache_lookup(connection_struct *conn, char *name; TALLOC_CTX *ctx = talloc_tos(); struct smb_filename smb_fname; + int ret; *pp_dirpath = NULL; *pp_start = *pp_name; @@ -283,7 +286,13 @@ bool stat_cache_lookup(connection_struct *conn, ZERO_STRUCT(smb_fname); smb_fname.base_name = translated_path; - if (SMB_VFS_STAT(conn, &smb_fname) != 0) { + if (posix_paths) { + ret = SMB_VFS_LSTAT(conn, &smb_fname); + } else { + ret = SMB_VFS_STAT(conn, &smb_fname); + } + + if (ret != 0) { /* Discard this entry - it doesn't exist in the filesystem. */ memcache_delete(smbd_memcache(), STAT_CACHE, data_blob_const(chk_name, strlen(chk_name))); -- 1.7.3.1 From 4fb4e0660bd241fe2cd16317926fddee48750443 Mon Sep 17 00:00:00 2001 From: Jeremy Allison Date: Fri, 21 Oct 2011 18:35:15 -0700 Subject: [PATCH 4/4] Third part of fix for bug #8541 - readlink() on Linux clients fails if the symlink target is outside of the share. Missed passing ucf_flags instead of hard coded flags in findfirst call. (cherry picked from commit 49d2a796bed0273327d8919755023c4dbd6d8232) --- source3/smbd/trans2.c | 3 +-- 1 files changed, 1 insertions(+), 2 deletions(-) diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c index 284635d..129ab01 100644 --- a/source3/smbd/trans2.c +++ b/source3/smbd/trans2.c @@ -2333,8 +2333,7 @@ close_if_end = %d requires_resume_key = %d level = 0x%x, max_data_bytes = %d\n", ntstatus = filename_convert(ctx, conn, req->flags2 & FLAGS2_DFS_PATHNAMES, directory, - (UCF_SAVE_LCOMP | - UCF_ALWAYS_ALLOW_WCARD_LCOMP), + ucf_flags, &mask_contains_wcard, &smb_dname); if (!NT_STATUS_IS_OK(ntstatus)) { -- 1.7.3.1