View | Details | Raw Unified | Return to bug 43678
Collapse All | Expand All

(-)a/source3/smbd/smb2_query_directory.c (-2 / +17 lines)
 Lines 24-29    Link Here 
24
#include "../libcli/smb/smb_common.h"
24
#include "../libcli/smb/smb_common.h"
25
#include "trans2.h"
25
#include "trans2.h"
26
#include "../lib/util/tevent_ntstatus.h"
26
#include "../lib/util/tevent_ntstatus.h"
27
#include "system/filesys.h"
27
28
28
static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx,
29
static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx,
29
					      struct tevent_context *ev,
30
					      struct tevent_context *ev,
 Lines 322-328   static struct tevent_req *smbd_smb2_query_directory_send(TALLOC_CTX *mem_ctx, Link Here 
322
	}
323
	}
323
324
324
	if (in_flags & SMB2_CONTINUE_FLAG_REOPEN) {
325
	if (in_flags & SMB2_CONTINUE_FLAG_REOPEN) {
326
		int flags;
327
325
		dptr_CloseDir(fsp);
328
		dptr_CloseDir(fsp);
329
330
		/*
331
		 * dptr_CloseDir() will close and invalidate the fsp's file
332
		 * descriptor, we have to reopen it.
333
		 */
334
335
		flags = O_RDONLY;
336
#ifdef O_DIRECTORY
337
		flags |= O_DIRECTORY;
338
#endif
339
		status = fd_open(conn, fsp, flags, 0);
340
		if (tevent_req_nterror(req, status)) {
341
			return tevent_req_post(req, ev);
342
		}
326
	}
343
	}
327
344
328
	if (!smbreq->posix_pathnames) {
345
	if (!smbreq->posix_pathnames) {
329
- 
330
SMB2_CONTINUE_FLAG_REOPEN flag
346
SMB2_CONTINUE_FLAG_REOPEN flag
331
--
332
source4/torture/smb2/dir.c | 12 ++++++++++--
347
source4/torture/smb2/dir.c | 12 ++++++++++--
333
1 file changed, 10 insertions(+), 2 deletions(-)
348
1 file changed, 10 insertions(+), 2 deletions(-)
(-)a/source4/torture/smb2/dir.c (-4 / +10 lines)
 Lines 674-680   bool fill_result(void *private_data, Link Here 
674
	return true;
674
	return true;
675
}
675
}
676
676
677
enum continue_type {CONT_SINGLE, CONT_INDEX, CONT_RESTART};
677
enum continue_type {CONT_SINGLE, CONT_INDEX, CONT_RESTART, CONT_REOPEN};
678
678
679
static NTSTATUS multiple_smb2_search(struct smb2_tree *tree,
679
static NTSTATUS multiple_smb2_search(struct smb2_tree *tree,
680
				     TALLOC_CTX *tctx,
680
				     TALLOC_CTX *tctx,
 Lines 700-705   static NTSTATUS multiple_smb2_search(struct smb2_tree *tree, Link Here 
700
700
701
	/* The search should start from the beginning everytime */
701
	/* The search should start from the beginning everytime */
702
	f.in.continue_flags = SMB2_CONTINUE_FLAG_RESTART;
702
	f.in.continue_flags = SMB2_CONTINUE_FLAG_RESTART;
703
	if (cont_type == CONT_REOPEN) {
704
		f.in.continue_flags = SMB2_CONTINUE_FLAG_REOPEN;
705
	}
703
706
704
	do {
707
	do {
705
		status = smb2_find_level(tree, tree, &f, &count, &d);
708
		status = smb2_find_level(tree, tree, &f, &count, &d);
 Lines 803-820   static bool test_many_files(struct torture_context *tctx, Link Here 
803
		{"SMB2_FIND_BOTH_DIRECTORY_INFO",    "SINGLE",  SMB2_FIND_BOTH_DIRECTORY_INFO,    RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,    CONT_SINGLE},
806
		{"SMB2_FIND_BOTH_DIRECTORY_INFO",    "SINGLE",  SMB2_FIND_BOTH_DIRECTORY_INFO,    RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,    CONT_SINGLE},
804
		{"SMB2_FIND_BOTH_DIRECTORY_INFO",    "INDEX",   SMB2_FIND_BOTH_DIRECTORY_INFO,    RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,    CONT_INDEX},
807
		{"SMB2_FIND_BOTH_DIRECTORY_INFO",    "INDEX",   SMB2_FIND_BOTH_DIRECTORY_INFO,    RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,    CONT_INDEX},
805
		{"SMB2_FIND_BOTH_DIRECTORY_INFO",    "RESTART", SMB2_FIND_BOTH_DIRECTORY_INFO,    RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,    CONT_RESTART},
808
		{"SMB2_FIND_BOTH_DIRECTORY_INFO",    "RESTART", SMB2_FIND_BOTH_DIRECTORY_INFO,    RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,    CONT_RESTART},
809
		{"SMB2_FIND_BOTH_DIRECTORY_INFO",    "REOPEN",  SMB2_FIND_BOTH_DIRECTORY_INFO,    RAW_SEARCH_DATA_BOTH_DIRECTORY_INFO,    CONT_REOPEN},
806
		{"SMB2_FIND_DIRECTORY_INFO",         "SINGLE",  SMB2_FIND_DIRECTORY_INFO,         RAW_SEARCH_DATA_DIRECTORY_INFO,         CONT_SINGLE},
810
		{"SMB2_FIND_DIRECTORY_INFO",         "SINGLE",  SMB2_FIND_DIRECTORY_INFO,         RAW_SEARCH_DATA_DIRECTORY_INFO,         CONT_SINGLE},
807
		{"SMB2_FIND_DIRECTORY_INFO",         "INDEX",   SMB2_FIND_DIRECTORY_INFO,         RAW_SEARCH_DATA_DIRECTORY_INFO,         CONT_INDEX},
811
		{"SMB2_FIND_DIRECTORY_INFO",         "INDEX",   SMB2_FIND_DIRECTORY_INFO,         RAW_SEARCH_DATA_DIRECTORY_INFO,         CONT_INDEX},
808
		{"SMB2_FIND_DIRECTORY_INFO",         "RESTART", SMB2_FIND_DIRECTORY_INFO,         RAW_SEARCH_DATA_DIRECTORY_INFO,         CONT_RESTART},
812
		{"SMB2_FIND_DIRECTORY_INFO",         "RESTART", SMB2_FIND_DIRECTORY_INFO,         RAW_SEARCH_DATA_DIRECTORY_INFO,         CONT_RESTART},
813
		{"SMB2_FIND_DIRECTORY_INFO",         "REOPEN",  SMB2_FIND_DIRECTORY_INFO,         RAW_SEARCH_DATA_DIRECTORY_INFO,         CONT_REOPEN},
809
		{"SMB2_FIND_FULL_DIRECTORY_INFO",    "SINGLE",  SMB2_FIND_FULL_DIRECTORY_INFO,    RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_SINGLE},
814
		{"SMB2_FIND_FULL_DIRECTORY_INFO",    "SINGLE",  SMB2_FIND_FULL_DIRECTORY_INFO,    RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_SINGLE},
810
		{"SMB2_FIND_FULL_DIRECTORY_INFO",    "INDEX",   SMB2_FIND_FULL_DIRECTORY_INFO,    RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_INDEX},
815
		{"SMB2_FIND_FULL_DIRECTORY_INFO",    "INDEX",   SMB2_FIND_FULL_DIRECTORY_INFO,    RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_INDEX},
811
		{"SMB2_FIND_FULL_DIRECTORY_INFO",    "RESTART", SMB2_FIND_FULL_DIRECTORY_INFO,    RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_RESTART},
816
		{"SMB2_FIND_FULL_DIRECTORY_INFO",    "RESTART", SMB2_FIND_FULL_DIRECTORY_INFO,    RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_RESTART},
817
		{"SMB2_FIND_FULL_DIRECTORY_INFO",    "REOPEN",  SMB2_FIND_FULL_DIRECTORY_INFO,    RAW_SEARCH_DATA_FULL_DIRECTORY_INFO,    CONT_REOPEN},
812
		{"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "SINGLE",  SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_SINGLE},
818
		{"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "SINGLE",  SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_SINGLE},
813
		{"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "INDEX",   SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_INDEX},
819
		{"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "INDEX",   SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_INDEX},
814
		{"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_RESTART},
820
		{"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_RESTART},
821
		{"SMB2_FIND_ID_FULL_DIRECTORY_INFO", "REOPEN",  SMB2_FIND_ID_FULL_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_FULL_DIRECTORY_INFO, CONT_REOPEN},
815
		{"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "SINGLE",  SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_SINGLE},
822
		{"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "SINGLE",  SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_SINGLE},
816
		{"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "INDEX",   SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_INDEX},
823
		{"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "INDEX",   SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_INDEX},
817
		{"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_RESTART}
824
		{"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "RESTART", SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_RESTART},
825
		{"SMB2_FIND_ID_BOTH_DIRECTORY_INFO", "REOPEN",  SMB2_FIND_ID_BOTH_DIRECTORY_INFO, RAW_SEARCH_DATA_ID_BOTH_DIRECTORY_INFO, CONT_REOPEN},
818
	};
826
	};
819
827
820
	smb2_deltree(tree, DNAME);
828
	smb2_deltree(tree, DNAME);
821
- 
822
OpenDir in preparation for making robust.
829
OpenDir in preparation for making robust.
823
--
824
source3/smbd/dir.c | 15 ++++++++++++++-
830
source3/smbd/dir.c | 15 ++++++++++++++-
825
1 file changed, 14 insertions(+), 1 deletion(-)
831
1 file changed, 14 insertions(+), 1 deletion(-)
(-)a/source3/smbd/dir.c (-3 / +14 lines)
 Lines 1630-1636   static int smb_Dir_destructor(struct smb_Dir *dirp) Link Here 
1630
 Open a directory.
1630
 Open a directory.
1631
********************************************************************/
1631
********************************************************************/
1632
1632
1633
struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1633
static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
1634
			connection_struct *conn,
1634
			const struct smb_filename *smb_dname,
1635
			const struct smb_filename *smb_dname,
1635
			const char *mask,
1636
			const char *mask,
1636
			uint32_t attr)
1637
			uint32_t attr)
 Lines 1672-1677   struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1672
	return NULL;
1673
	return NULL;
1673
}
1674
}
1674
1675
1676
struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1677
			const struct smb_filename *smb_dname,
1678
			const char *mask,
1679
			uint32_t attr)
1680
{
1681
	return OpenDir_internal(mem_ctx,
1682
				conn,
1683
				smb_dname,
1684
				mask,
1685
				attr);
1686
}
1687
1675
/*******************************************************************
1688
/*******************************************************************
1676
 Open a directory from an fsp.
1689
 Open a directory from an fsp.
1677
********************************************************************/
1690
********************************************************************/
1678
- 
1679
return if SMB_VFS_OPENDIR failed.
1691
return if SMB_VFS_OPENDIR failed.
1680
--
1681
source3/smbd/dir.c | 18 +++++++++---------
1692
source3/smbd/dir.c | 18 +++++++++---------
1682
1 file changed, 9 insertions(+), 9 deletions(-)
1693
1 file changed, 9 insertions(+), 9 deletions(-)
(-)a/source3/smbd/dir.c (-11 / +9 lines)
 Lines 1643-1648   static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx, Link Here 
1643
		return NULL;
1643
		return NULL;
1644
	}
1644
	}
1645
1645
1646
	dirp->dir = SMB_VFS_OPENDIR(conn, smb_dname, mask, attr);
1647
1648
	if (!dirp->dir) {
1649
		DEBUG(5,("OpenDir: Can't open %s. %s\n",
1650
			smb_dname->base_name,
1651
			strerror(errno) ));
1652
		goto fail;
1653
	}
1654
1646
	dirp->conn = conn;
1655
	dirp->conn = conn;
1647
	dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1656
	dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1648
1657
 Lines 1657-1671   static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx, Link Here 
1657
	}
1666
	}
1658
	talloc_set_destructor(dirp, smb_Dir_destructor);
1667
	talloc_set_destructor(dirp, smb_Dir_destructor);
1659
1668
1660
	dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_smb_fname, mask, attr);
1661
1662
	if (!dirp->dir) {
1663
		DEBUG(5,("OpenDir: Can't open %s. %s\n",
1664
			dirp->dir_smb_fname->base_name,
1665
			strerror(errno) ));
1666
		goto fail;
1667
	}
1668
1669
	return dirp;
1669
	return dirp;
1670
1670
1671
  fail:
1671
  fail:
1672
- 
1673
open_dir_safely(). Use from OpenDir().
1672
open_dir_safely(). Use from OpenDir().
1674
--
1675
source3/smbd/dir.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++-----
1673
source3/smbd/dir.c | 77 +++++++++++++++++++++++++++++++++++++++++++++++++-----
1676
1 file changed, 70 insertions(+), 7 deletions(-)
1674
1 file changed, 70 insertions(+), 7 deletions(-)
(-)a/source3/smbd/dir.c (-9 / +70 lines)
 Lines 1655-1666   static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx, Link Here 
1655
	dirp->conn = conn;
1655
	dirp->conn = conn;
1656
	dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1656
	dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1657
1657
1658
	dirp->dir_smb_fname = cp_smb_filename(dirp, smb_dname);
1659
	if (!dirp->dir_smb_fname) {
1660
		errno = ENOMEM;
1661
		goto fail;
1662
	}
1663
1664
	if (sconn && !sconn->using_smb2) {
1658
	if (sconn && !sconn->using_smb2) {
1665
		sconn->searches.dirhandles_open++;
1659
		sconn->searches.dirhandles_open++;
1666
	}
1660
	}
 Lines 1673-1684   static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx, Link Here 
1673
	return NULL;
1667
	return NULL;
1674
}
1668
}
1675
1669
1670
/****************************************************************************
1671
 Open a directory handle by pathname, ensuring it's under the share path.
1672
****************************************************************************/
1673
1674
static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
1675
					connection_struct *conn,
1676
					const struct smb_filename *smb_dname,
1677
					const char *wcard,
1678
					uint32_t attr)
1679
{
1680
	struct smb_Dir *dir_hnd = NULL;
1681
	struct smb_filename *smb_fname_cwd = NULL;
1682
	char *saved_dir = vfs_GetWd(ctx, conn);
1683
	NTSTATUS status;
1684
1685
	if (saved_dir == NULL) {
1686
		return NULL;
1687
	}
1688
1689
	if (vfs_ChDir(conn, smb_dname->base_name) == -1) {
1690
		goto out;
1691
	}
1692
1693
	smb_fname_cwd = synthetic_smb_fname(talloc_tos(),
1694
					".",
1695
					NULL,
1696
					NULL,
1697
					smb_dname->flags);
1698
	if (smb_fname_cwd == NULL) {
1699
		goto out;
1700
	}
1701
1702
	/*
1703
	 * Now the directory is pinned, use
1704
	 * REALPATH to ensure we can access it.
1705
	 */
1706
	status = check_name(conn, ".");
1707
	if (!NT_STATUS_IS_OK(status)) {
1708
		goto out;
1709
	}
1710
1711
	dir_hnd = OpenDir_internal(ctx,
1712
				conn,
1713
				smb_fname_cwd,
1714
				wcard,
1715
				attr);
1716
1717
	if (dir_hnd == NULL) {
1718
		goto out;
1719
	}
1720
1721
	/*
1722
	 * OpenDir_internal only gets "." as the dir name.
1723
	 * Store the real dir name here.
1724
	 */
1725
1726
	dir_hnd->dir_smb_fname = cp_smb_filename(dir_hnd, smb_dname);
1727
	if (!dir_hnd->dir_smb_fname) {
1728
		TALLOC_FREE(dir_hnd);
1729
		errno = ENOMEM;
1730
	}
1731
1732
  out:
1733
1734
	vfs_ChDir(conn, saved_dir);
1735
	TALLOC_FREE(saved_dir);
1736
	return dir_hnd;
1737
}
1738
1676
struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1739
struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1677
			const struct smb_filename *smb_dname,
1740
			const struct smb_filename *smb_dname,
1678
			const char *mask,
1741
			const char *mask,
1679
			uint32_t attr)
1742
			uint32_t attr)
1680
{
1743
{
1681
	return OpenDir_internal(mem_ctx,
1744
	return open_dir_safely(mem_ctx,
1682
				conn,
1745
				conn,
1683
				smb_dname,
1746
				smb_dname,
1684
				mask,
1747
				mask,
1685
- 
1686
returns.
1748
returns.
1687
--
1688
source3/smbd/dir.c | 34 +++++++++++++++++++++-------------
1749
source3/smbd/dir.c | 34 +++++++++++++++++++++-------------
1689
1 file changed, 21 insertions(+), 13 deletions(-)
1750
1 file changed, 21 insertions(+), 13 deletions(-)
(-)a/source3/smbd/dir.c (-15 / +21 lines)
 Lines 1761-1767   static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1761
	struct smbd_server_connection *sconn = conn->sconn;
1761
	struct smbd_server_connection *sconn = conn->sconn;
1762
1762
1763
	if (!dirp) {
1763
	if (!dirp) {
1764
		return NULL;
1764
		goto fail;
1765
	}
1766
1767
	if (!fsp->is_directory) {
1768
		errno = EBADF;
1769
		goto fail;
1770
	}
1771
1772
	if (fsp->fh->fd == -1) {
1773
		errno = EBADF;
1774
		goto fail;
1765
	}
1775
	}
1766
1776
1767
	dirp->conn = conn;
1777
	dirp->conn = conn;
 Lines 1778-1795   static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1778
	}
1788
	}
1779
	talloc_set_destructor(dirp, smb_Dir_destructor);
1789
	talloc_set_destructor(dirp, smb_Dir_destructor);
1780
1790
1781
	if (fsp->is_directory && fsp->fh->fd != -1) {
1791
	dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1782
		dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1792
	if (dirp->dir != NULL) {
1783
		if (dirp->dir != NULL) {
1793
		dirp->fsp = fsp;
1784
			dirp->fsp = fsp;
1794
	} else {
1785
		} else {
1795
		DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1786
			DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1796
			"NULL (%s)\n",
1787
				"NULL (%s)\n",
1797
			dirp->dir_smb_fname->base_name,
1788
				dirp->dir_smb_fname->base_name,
1798
			strerror(errno)));
1789
				strerror(errno)));
1799
		if (errno != ENOSYS) {
1790
			if (errno != ENOSYS) {
1800
			return NULL;
1791
				return NULL;
1792
			}
1793
		}
1801
		}
1794
	}
1802
	}
1795
1803
1796
- 
1797
leak on error.
1804
leak on error.
1798
--
1799
source3/smbd/dir.c | 2 +-
1805
source3/smbd/dir.c | 2 +-
1800
1 file changed, 1 insertion(+), 1 deletion(-)
1806
1 file changed, 1 insertion(+), 1 deletion(-)
(-)a/source3/smbd/dir.c (-3 / +1 lines)
 Lines 1797-1803   static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1797
			dirp->dir_smb_fname->base_name,
1797
			dirp->dir_smb_fname->base_name,
1798
			strerror(errno)));
1798
			strerror(errno)));
1799
		if (errno != ENOSYS) {
1799
		if (errno != ENOSYS) {
1800
			return NULL;
1800
			goto fail;
1801
		}
1801
		}
1802
	}
1802
	}
1803
1803
1804
- 
1805
and destructor setup to just before retuning success.
1804
and destructor setup to just before retuning success.
1806
--
1807
source3/smbd/dir.c | 10 +++++-----
1805
source3/smbd/dir.c | 10 +++++-----
1808
1 file changed, 5 insertions(+), 5 deletions(-)
1806
1 file changed, 5 insertions(+), 5 deletions(-)
(-)a/source3/smbd/dir.c (-7 / +5 lines)
 Lines 1783-1793   static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1783
		goto fail;
1783
		goto fail;
1784
	}
1784
	}
1785
1785
1786
	if (sconn && !sconn->using_smb2) {
1787
		sconn->searches.dirhandles_open++;
1788
	}
1789
	talloc_set_destructor(dirp, smb_Dir_destructor);
1790
1791
	dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1786
	dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1792
	if (dirp->dir != NULL) {
1787
	if (dirp->dir != NULL) {
1793
		dirp->fsp = fsp;
1788
		dirp->fsp = fsp;
 Lines 1816-1821   static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1816
		goto fail;
1811
		goto fail;
1817
	}
1812
	}
1818
1813
1814
	if (sconn && !sconn->using_smb2) {
1815
		sconn->searches.dirhandles_open++;
1816
	}
1817
	talloc_set_destructor(dirp, smb_Dir_destructor);
1818
1819
	return dirp;
1819
	return dirp;
1820
1820
1821
  fail:
1821
  fail:
1822
- 
1823
open_dir_safely if FDOPENDIR not supported on system.
1822
open_dir_safely if FDOPENDIR not supported on system.
1824
--
1825
source3/smbd/dir.c | 15 +++++----------
1823
source3/smbd/dir.c | 15 +++++----------
1826
1 file changed, 5 insertions(+), 10 deletions(-)
1824
1 file changed, 5 insertions(+), 10 deletions(-)
(-)a/source3/smbd/dir.c (-12 / +5 lines)
 Lines 1797-1816   static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1797
	}
1797
	}
1798
1798
1799
	if (dirp->dir == NULL) {
1799
	if (dirp->dir == NULL) {
1800
		/* FDOPENDIR didn't work. Use OPENDIR instead. */
1800
		/* FDOPENDIR is not supported. Use OPENDIR instead. */
1801
		dirp->dir = SMB_VFS_OPENDIR(conn,
1801
		TALLOC_FREE(dirp);
1802
					dirp->dir_smb_fname,
1802
		return open_dir_safely(mem_ctx,
1803
					conn,
1804
					fsp->fsp_name,
1803
					mask,
1805
					mask,
1804
					attr);
1806
					attr);
1805
	}
1807
	}
1806
1808
1807
	if (!dirp->dir) {
1808
		DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n",
1809
			dirp->dir_smb_fname->base_name,
1810
			strerror(errno) ));
1811
		goto fail;
1812
	}
1813
1814
	if (sconn && !sconn->using_smb2) {
1809
	if (sconn && !sconn->using_smb2) {
1815
		sconn->searches.dirhandles_open++;
1810
		sconn->searches.dirhandles_open++;
1816
	}
1811
	}
1817
- 
1818
insist on O_NOFOLLOW existing.
1812
insist on O_NOFOLLOW existing.
1819
--
1820
source3/smbd/open.c | 6 +-----
1813
source3/smbd/open.c | 6 +-----
1821
1 file changed, 1 insertion(+), 5 deletions(-)
1814
1 file changed, 1 insertion(+), 5 deletions(-)
(-)a/source3/smbd/open.c (-7 / +1 lines)
 Lines 366-373   NTSTATUS fd_open(struct connection_struct *conn, Link Here 
366
	struct smb_filename *smb_fname = fsp->fsp_name;
366
	struct smb_filename *smb_fname = fsp->fsp_name;
367
	NTSTATUS status = NT_STATUS_OK;
367
	NTSTATUS status = NT_STATUS_OK;
368
368
369
#ifdef O_NOFOLLOW
369
	/*
370
	/* 
371
	 * Never follow symlinks on a POSIX client. The
370
	 * Never follow symlinks on a POSIX client. The
372
	 * client should be doing this.
371
	 * client should be doing this.
373
	 */
372
	 */
 Lines 375-386   NTSTATUS fd_open(struct connection_struct *conn, Link Here 
375
	if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) || !lp_follow_symlinks(SNUM(conn))) {
374
	if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) || !lp_follow_symlinks(SNUM(conn))) {
376
		flags |= O_NOFOLLOW;
375
		flags |= O_NOFOLLOW;
377
	}
376
	}
378
#endif
379
377
380
	fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
378
	fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
381
	if (fsp->fh->fd == -1) {
379
	if (fsp->fh->fd == -1) {
382
		int posix_errno = errno;
380
		int posix_errno = errno;
383
#ifdef O_NOFOLLOW
384
#if defined(ENOTSUP) && defined(OSF1)
381
#if defined(ENOTSUP) && defined(OSF1)
385
		/* handle special Tru64 errno */
382
		/* handle special Tru64 errno */
386
		if (errno == ENOTSUP) {
383
		if (errno == ENOTSUP) {
 Lines 397-403   NTSTATUS fd_open(struct connection_struct *conn, Link Here 
397
		if (errno == EMLINK) {
394
		if (errno == EMLINK) {
398
			posix_errno = ELOOP;
395
			posix_errno = ELOOP;
399
		}
396
		}
400
#endif /* O_NOFOLLOW */
401
		status = map_nt_error_from_unix(posix_errno);
397
		status = map_nt_error_from_unix(posix_errno);
402
		if (errno == EMFILE) {
398
		if (errno == EMFILE) {
403
			static time_t last_warned = 0L;
399
			static time_t last_warned = 0L;
404
- 
405
symlink errno's into a utility function.
400
symlink errno's into a utility function.
406
--
407
source3/smbd/open.c | 43 ++++++++++++++++++++++++++-----------------
401
source3/smbd/open.c | 43 ++++++++++++++++++++++++++-----------------
408
1 file changed, 26 insertions(+), 17 deletions(-)
402
1 file changed, 26 insertions(+), 17 deletions(-)
(-)a/source3/smbd/open.c (-19 / +26 lines)
 Lines 355-360   static NTSTATUS check_base_file_access(struct connection_struct *conn, Link Here 
355
}
355
}
356
356
357
/****************************************************************************
357
/****************************************************************************
358
 Handle differing symlink errno's
359
****************************************************************************/
360
361
static int link_errno_convert(int err)
362
{
363
#if defined(ENOTSUP) && defined(OSF1)
364
	/* handle special Tru64 errno */
365
	if (err == ENOTSUP) {
366
		err = ELOOP;
367
	}
368
#endif /* ENOTSUP */
369
#ifdef EFTYPE
370
	/* fix broken NetBSD errno */
371
	if (err == EFTYPE) {
372
		err = ELOOP;
373
	}
374
#endif /* EFTYPE */
375
	/* fix broken FreeBSD errno */
376
	if (err == EMLINK) {
377
		err = ELOOP;
378
	}
379
	return err;
380
}
381
382
/****************************************************************************
358
 fd support routines - attempt to do a dos_open.
383
 fd support routines - attempt to do a dos_open.
359
****************************************************************************/
384
****************************************************************************/
360
385
 Lines 377-399   NTSTATUS fd_open(struct connection_struct *conn, Link Here 
377
402
378
	fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
403
	fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
379
	if (fsp->fh->fd == -1) {
404
	if (fsp->fh->fd == -1) {
380
		int posix_errno = errno;
405
		int posix_errno = link_errno_convert(errno);
381
#if defined(ENOTSUP) && defined(OSF1)
382
		/* handle special Tru64 errno */
383
		if (errno == ENOTSUP) {
384
			posix_errno = ELOOP;
385
		}
386
#endif /* ENOTSUP */
387
#ifdef EFTYPE
388
		/* fix broken NetBSD errno */
389
		if (errno == EFTYPE) {
390
			posix_errno = ELOOP;
391
		}
392
#endif /* EFTYPE */
393
		/* fix broken FreeBSD errno */
394
		if (errno == EMLINK) {
395
			posix_errno = ELOOP;
396
		}
397
		status = map_nt_error_from_unix(posix_errno);
406
		status = map_nt_error_from_unix(posix_errno);
398
		if (errno == EMFILE) {
407
		if (errno == EMFILE) {
399
			static time_t last_warned = 0L;
408
			static time_t last_warned = 0L;
400
- 
401
prevent symlink open races.
409
prevent symlink open races.
402
--
403
source3/smbd/open.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++
410
source3/smbd/open.c | 238 ++++++++++++++++++++++++++++++++++++++++++++++++++++
404
1 file changed, 238 insertions(+)
411
1 file changed, 238 insertions(+)
(-)a/source3/smbd/open.c (-2 / +238 lines)
 Lines 379-384   static int link_errno_convert(int err) Link Here 
379
	return err;
379
	return err;
380
}
380
}
381
381
382
static int non_widelink_open(struct connection_struct *conn,
383
			const char *conn_rootdir,
384
			files_struct *fsp,
385
			struct smb_filename *smb_fname,
386
			int flags,
387
			mode_t mode,
388
			unsigned int link_depth);
389
390
/****************************************************************************
391
 Follow a symlink in userspace.
392
****************************************************************************/
393
394
static int process_symlink_open(struct connection_struct *conn,
395
			const char *conn_rootdir,
396
			files_struct *fsp,
397
			struct smb_filename *smb_fname,
398
			int flags,
399
			mode_t mode,
400
			unsigned int link_depth)
401
{
402
	int fd = -1;
403
	char *link_target = NULL;
404
	int link_len = -1;
405
	char *oldwd = NULL;
406
	size_t rootdir_len = 0;
407
	char *resolved_name = NULL;
408
	bool matched = false;
409
	int saved_errno = 0;
410
411
	/*
412
	 * Ensure we don't get stuck in a symlink loop.
413
	 */
414
	link_depth++;
415
	if (link_depth >= 20) {
416
		errno = ELOOP;
417
		goto out;
418
	}
419
420
	/* Allocate space for the link target. */
421
	link_target = talloc_array(talloc_tos(), char, PATH_MAX);
422
	if (link_target == NULL) {
423
		errno = ENOMEM;
424
		goto out;
425
	}
426
427
	/* Read the link target. */
428
	link_len = SMB_VFS_READLINK(conn,
429
				smb_fname->base_name,
430
				link_target,
431
				PATH_MAX - 1);
432
	if (link_len == -1) {
433
		goto out;
434
	}
435
436
	/* Ensure it's at least null terminated. */
437
	link_target[link_len] = '\0';
438
439
	/* Convert to an absolute path. */
440
	resolved_name = SMB_VFS_REALPATH(conn, link_target);
441
	if (resolved_name == NULL) {
442
		goto out;
443
	}
444
445
	/*
446
	 * We know conn_rootdir starts with '/' and
447
	 * does not end in '/'. FIXME ! Should we
448
	 * smb_assert this ?
449
	 */
450
	rootdir_len = strlen(conn_rootdir);
451
452
	matched = (strncmp(conn_rootdir, resolved_name, rootdir_len) == 0);
453
	if (!matched) {
454
		errno = EACCES;
455
		goto out;
456
	}
457
458
	/*
459
	 * Turn into a path relative to the share root.
460
	 */
461
	if (resolved_name[rootdir_len] == '\0') {
462
		/* Link to the root of the share. */
463
		smb_fname->base_name = talloc_strdup(talloc_tos(), ".");
464
		if (smb_fname->base_name == NULL) {
465
			errno = ENOMEM;
466
			goto out;
467
		}
468
	} else if (resolved_name[rootdir_len] == '/') {
469
		smb_fname->base_name = &resolved_name[rootdir_len+1];
470
	} else {
471
		errno = EACCES;
472
		goto out;
473
	}
474
475
	oldwd = vfs_GetWd(talloc_tos(), conn);
476
	if (oldwd == NULL) {
477
		goto out;
478
	}
479
480
	/* Ensure we operate from the root of the share. */
481
	if (vfs_ChDir(conn, conn_rootdir) == -1) {
482
		goto out;
483
	}
484
485
	/* And do it all again.. */
486
	fd = non_widelink_open(conn,
487
				conn_rootdir,
488
				fsp,
489
				smb_fname,
490
				flags,
491
				mode,
492
				link_depth);
493
	if (fd == -1) {
494
		saved_errno = errno;
495
	}
496
497
  out:
498
499
	SAFE_FREE(resolved_name);
500
	TALLOC_FREE(link_target);
501
	if (oldwd != NULL) {
502
		int ret = vfs_ChDir(conn, oldwd);
503
		if (ret == -1) {
504
			smb_panic("unable to get back to old directory\n");
505
		}
506
		TALLOC_FREE(oldwd);
507
	}
508
	if (saved_errno != 0) {
509
		errno = saved_errno;
510
	}
511
	return fd;
512
}
513
514
/****************************************************************************
515
 Non-widelink open.
516
****************************************************************************/
517
518
static int non_widelink_open(struct connection_struct *conn,
519
			const char *conn_rootdir,
520
			files_struct *fsp,
521
			struct smb_filename *smb_fname,
522
			int flags,
523
			mode_t mode,
524
			unsigned int link_depth)
525
{
526
	NTSTATUS status;
527
	int fd = -1;
528
	struct smb_filename *smb_fname_rel = NULL;
529
	int saved_errno = 0;
530
	char *oldwd = NULL;
531
	char *parent_dir = NULL;
532
	const char *final_component = NULL;
533
534
	if (!parent_dirname(talloc_tos(),
535
			smb_fname->base_name,
536
			&parent_dir,
537
			&final_component)) {
538
		goto out;
539
	}
540
541
	oldwd = vfs_GetWd(talloc_tos(), conn);
542
	if (oldwd == NULL) {
543
		goto out;
544
	}
545
546
	/* Pin parent directory in place. */
547
	if (vfs_ChDir(conn, parent_dir) == -1) {
548
		goto out;
549
	}
550
551
	/* Ensure the relative path is below the share. */
552
	status = check_reduced_name(conn, final_component);
553
	if (!NT_STATUS_IS_OK(status)) {
554
		saved_errno = map_errno_from_nt_status(status);
555
		goto out;
556
	}
557
558
	smb_fname_rel = synthetic_smb_fname(talloc_tos(),
559
				final_component,
560
				smb_fname->stream_name,
561
				&smb_fname->st,
562
				smb_fname->flags);
563
564
	flags |= O_NOFOLLOW;
565
566
	{
567
		struct smb_filename *tmp_name = fsp->fsp_name;
568
		fsp->fsp_name = smb_fname_rel;
569
		fd = SMB_VFS_OPEN(conn, smb_fname_rel, fsp, flags, mode);
570
		fsp->fsp_name = tmp_name;
571
	}
572
573
	if (fd == -1) {
574
		saved_errno = link_errno_convert(errno);
575
		if (saved_errno == ELOOP) {
576
			if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
577
				/* Never follow symlinks on posix open. */
578
				goto out;
579
			}
580
			if (!lp_follow_symlinks(SNUM(conn))) {
581
				/* Explicitly no symlinks. */
582
				goto out;
583
			}
584
			/*
585
			 * We have a symlink. Follow in userspace
586
			 * to ensure it's under the share definition.
587
			 */
588
			fd = process_symlink_open(conn,
589
					conn_rootdir,
590
					fsp,
591
					smb_fname_rel,
592
					flags,
593
					mode,
594
					link_depth);
595
			if (fd == -1) {
596
				saved_errno =
597
					link_errno_convert(errno);
598
			}
599
		}
600
	}
601
602
  out:
603
604
	TALLOC_FREE(parent_dir);
605
	TALLOC_FREE(smb_fname_rel);
606
607
	if (oldwd != NULL) {
608
		int ret = vfs_ChDir(conn, oldwd);
609
		if (ret == -1) {
610
			smb_panic("unable to get back to old directory\n");
611
		}
612
		TALLOC_FREE(oldwd);
613
	}
614
	if (saved_errno != 0) {
615
		errno = saved_errno;
616
	}
617
	return fd;
618
}
619
382
/****************************************************************************
620
/****************************************************************************
383
 fd support routines - attempt to do a dos_open.
621
 fd support routines - attempt to do a dos_open.
384
****************************************************************************/
622
****************************************************************************/
385
- 
386
non_widelink_open() function.
623
non_widelink_open() function.
387
--
388
source3/smbd/open.c | 23 ++++++++++++++++++++++-
624
source3/smbd/open.c | 23 ++++++++++++++++++++++-
389
1 file changed, 22 insertions(+), 1 deletion(-)
625
1 file changed, 22 insertions(+), 1 deletion(-)
(-)a/source3/smbd/open.c (-2 / +22 lines)
 Lines 638-644   NTSTATUS fd_open(struct connection_struct *conn, Link Here 
638
		flags |= O_NOFOLLOW;
638
		flags |= O_NOFOLLOW;
639
	}
639
	}
640
640
641
	fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
641
	/* Ensure path is below share definition. */
642
	if (!lp_widelinks(SNUM(conn))) {
643
		const char *conn_rootdir = SMB_VFS_CONNECTPATH(conn,
644
						smb_fname->base_name);
645
		if (conn_rootdir == NULL) {
646
			return NT_STATUS_NO_MEMORY;
647
		}
648
		/*
649
		 * Only follow symlinks within a share
650
		 * definition.
651
		 */
652
		fsp->fh->fd = non_widelink_open(conn,
653
					conn_rootdir,
654
					fsp,
655
					smb_fname,
656
					flags,
657
					mode,
658
					0);
659
	} else {
660
		fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
661
	}
662
642
	if (fsp->fh->fd == -1) {
663
	if (fsp->fh->fd == -1) {
643
		int posix_errno = link_errno_convert(errno);
664
		int posix_errno = link_errno_convert(errno);
644
		status = map_nt_error_from_unix(posix_errno);
665
		status = map_nt_error_from_unix(posix_errno);
645
- 

Return to bug 43678