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

(-)a/source3/smbd/dir.c (-3 / +14 lines)
 Lines 1588-1594   static int smb_Dir_destructor(struct smb_Dir *dirp) Link Here 
1588
 Open a directory.
1588
 Open a directory.
1589
********************************************************************/
1589
********************************************************************/
1590
1590
1591
struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1591
static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx,
1592
			connection_struct *conn,
1592
			const char *name,
1593
			const char *name,
1593
			const char *mask,
1594
			const char *mask,
1594
			uint32_t attr)
1595
			uint32_t attr)
 Lines 1628-1633   struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1628
	return NULL;
1629
	return NULL;
1629
}
1630
}
1630
1631
1632
struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1633
			const char *name,
1634
			const char *mask,
1635
			uint32_t attr)
1636
{
1637
	return OpenDir_internal(mem_ctx,
1638
				conn,
1639
				name,
1640
				mask,
1641
				attr);
1642
}
1643
1631
/*******************************************************************
1644
/*******************************************************************
1632
 Open a directory from an fsp.
1645
 Open a directory from an fsp.
1633
********************************************************************/
1646
********************************************************************/
1634
- 
1635
SMB_VFS_OPENDIR failed.
1647
SMB_VFS_OPENDIR failed.
1636
--
1637
source3/smbd/dir.c | 16 ++++++++--------
1648
source3/smbd/dir.c | 16 ++++++++--------
1638
1 file changed, 8 insertions(+), 8 deletions(-)
1649
1 file changed, 8 insertions(+), 8 deletions(-)
(-)a/source3/smbd/dir.c (-10 / +8 lines)
 Lines 1601-1620   static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx, Link Here 
1601
		return NULL;
1601
		return NULL;
1602
	}
1602
	}
1603
1603
1604
	dirp->conn = conn;
1605
	dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1606
1607
	dirp->dir_path = talloc_strdup(dirp, name);
1604
	dirp->dir_path = talloc_strdup(dirp, name);
1608
	if (!dirp->dir_path) {
1605
	if (!dirp->dir_path) {
1609
		errno = ENOMEM;
1606
		errno = ENOMEM;
1610
		goto fail;
1607
		goto fail;
1611
	}
1608
	}
1612
1609
1613
	if (sconn && !sconn->using_smb2) {
1614
		sconn->searches.dirhandles_open++;
1615
	}
1616
	talloc_set_destructor(dirp, smb_Dir_destructor);
1617
1618
	dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1610
	dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1619
	if (!dirp->dir) {
1611
	if (!dirp->dir) {
1620
		DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1612
		DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
 Lines 1622-1627   static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx, Link Here 
1622
		goto fail;
1614
		goto fail;
1623
	}
1615
	}
1624
1616
1617
	dirp->conn = conn;
1618
	dirp->name_cache_size = lp_directory_name_cache_size(SNUM(conn));
1619
1620
	if (sconn && !sconn->using_smb2) {
1621
		sconn->searches.dirhandles_open++;
1622
	}
1623
	talloc_set_destructor(dirp, smb_Dir_destructor);
1624
1625
	return dirp;
1625
	return dirp;
1626
1626
1627
  fail:
1627
  fail:
1628
- 
1629
OpenDir().
1628
OpenDir().
1630
--
1631
source3/smbd/dir.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++-------
1629
source3/smbd/dir.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++-------
1632
1 file changed, 61 insertions(+), 9 deletions(-)
1630
1 file changed, 61 insertions(+), 9 deletions(-)
(-)a/source3/smbd/dir.c (-11 / +61 lines)
 Lines 1601-1615   static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx, Link Here 
1601
		return NULL;
1601
		return NULL;
1602
	}
1602
	}
1603
1603
1604
	dirp->dir_path = talloc_strdup(dirp, name);
1604
	dirp->dir = SMB_VFS_OPENDIR(conn, name, mask, attr);
1605
	if (!dirp->dir_path) {
1606
		errno = ENOMEM;
1607
		goto fail;
1608
	}
1609
1610
	dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1611
	if (!dirp->dir) {
1605
	if (!dirp->dir) {
1612
		DEBUG(5,("OpenDir: Can't open %s. %s\n", dirp->dir_path,
1606
		DEBUG(5,("OpenDir: Can't open %s. %s\n", name,
1613
			 strerror(errno) ));
1607
			 strerror(errno) ));
1614
		goto fail;
1608
		goto fail;
1615
	}
1609
	}
 Lines 1629-1640   static struct smb_Dir *OpenDir_internal(TALLOC_CTX *mem_ctx, Link Here 
1629
	return NULL;
1623
	return NULL;
1630
}
1624
}
1631
1625
1626
/****************************************************************************
1627
 Open a directory handle by pathname, ensuring it's under the share path.
1628
****************************************************************************/
1629
1630
static struct smb_Dir *open_dir_safely(TALLOC_CTX *ctx,
1631
					connection_struct *conn,
1632
					const char *name,
1633
					const char *wcard,
1634
					uint32_t attr)
1635
{
1636
	struct smb_Dir *dir_hnd = NULL;
1637
	char *saved_dir = vfs_GetWd(ctx, conn);
1638
	NTSTATUS status;
1639
1640
	if (saved_dir == NULL) {
1641
		return NULL;
1642
	}
1643
1644
	if (vfs_ChDir(conn, name) == -1) {
1645
		goto out;
1646
	}
1647
1648
	/*
1649
	 * Now the directory is pinned, use
1650
	 * REALPATH to ensure we can access it.
1651
	 */
1652
	status = check_name(conn, ".");
1653
	if (!NT_STATUS_IS_OK(status)) {
1654
		goto out;
1655
	}
1656
1657
	dir_hnd = OpenDir_internal(ctx,
1658
				conn,
1659
				".",
1660
				wcard,
1661
				attr);
1662
1663
	if (dir_hnd == NULL) {
1664
		goto out;
1665
	}
1666
1667
	/*
1668
	 * OpenDir_internal only gets "." as the dir name.
1669
	 * Store the real dir name here.
1670
	 */
1671
1672
	dir_hnd->dir_path = talloc_strdup(dir_hnd, name);
1673
	if (!dir_hnd->dir_path) {
1674
		errno = ENOMEM;
1675
	}
1676
1677
  out:
1678
1679
	vfs_ChDir(conn, saved_dir);
1680
	TALLOC_FREE(saved_dir);
1681
	return dir_hnd;
1682
}
1683
1632
struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1684
struct smb_Dir *OpenDir(TALLOC_CTX *mem_ctx, connection_struct *conn,
1633
			const char *name,
1685
			const char *name,
1634
			const char *mask,
1686
			const char *mask,
1635
			uint32_t attr)
1687
			uint32_t attr)
1636
{
1688
{
1637
	return OpenDir_internal(mem_ctx,
1689
	return open_dir_safely(mem_ctx,
1638
				conn,
1690
				conn,
1639
				name,
1691
				name,
1640
				mask,
1692
				mask,
1641
- 
1642
--
1643
source3/smbd/dir.c | 34 +++++++++++++++++++++-------------
1693
source3/smbd/dir.c | 34 +++++++++++++++++++++-------------
1644
1 file changed, 21 insertions(+), 13 deletions(-)
1694
1 file changed, 21 insertions(+), 13 deletions(-)
(-)a/source3/smbd/dir.c (-15 / +21 lines)
 Lines 1706-1712   static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1706
	struct smbd_server_connection *sconn = conn->sconn;
1706
	struct smbd_server_connection *sconn = conn->sconn;
1707
1707
1708
	if (!dirp) {
1708
	if (!dirp) {
1709
		return NULL;
1709
		goto fail;
1710
	}
1711
1712
	if (!fsp->is_directory) {
1713
		errno = EBADF;
1714
		goto fail;
1715
	}
1716
1717
	if (fsp->fh->fd == -1) {
1718
		errno = EBADF;
1719
		goto fail;
1710
	}
1720
	}
1711
1721
1712
	dirp->conn = conn;
1722
	dirp->conn = conn;
 Lines 1723-1740   static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1723
	}
1733
	}
1724
	talloc_set_destructor(dirp, smb_Dir_destructor);
1734
	talloc_set_destructor(dirp, smb_Dir_destructor);
1725
1735
1726
	if (fsp->is_directory && fsp->fh->fd != -1) {
1736
	dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1727
		dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1737
	if (dirp->dir != NULL) {
1728
		if (dirp->dir != NULL) {
1738
		dirp->fsp = fsp;
1729
			dirp->fsp = fsp;
1739
	} else {
1730
		} else {
1740
		DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1731
			DEBUG(10,("OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
1741
			"NULL (%s)\n",
1732
				"NULL (%s)\n",
1742
			dirp->dir_path,
1733
				dirp->dir_path,
1743
			strerror(errno)));
1734
				strerror(errno)));
1744
		if (errno != ENOSYS) {
1735
			if (errno != ENOSYS) {
1745
			return NULL;
1736
				return NULL;
1737
			}
1738
		}
1746
		}
1739
	}
1747
	}
1740
1748
1741
- 
1742
--
1743
source3/smbd/dir.c | 2 +-
1749
source3/smbd/dir.c | 2 +-
1744
1 file changed, 1 insertion(+), 1 deletion(-)
1750
1 file changed, 1 insertion(+), 1 deletion(-)
(-)a/source3/smbd/dir.c (-3 / +1 lines)
 Lines 1742-1748   static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1742
			dirp->dir_path,
1742
			dirp->dir_path,
1743
			strerror(errno)));
1743
			strerror(errno)));
1744
		if (errno != ENOSYS) {
1744
		if (errno != ENOSYS) {
1745
			return NULL;
1745
			goto fail;
1746
		}
1746
		}
1747
	}
1747
	}
1748
1748
1749
- 
1750
setup to just before retuning success.
1749
setup to just before retuning success.
1751
--
1752
source3/smbd/dir.c | 10 +++++-----
1750
source3/smbd/dir.c | 10 +++++-----
1753
1 file changed, 5 insertions(+), 5 deletions(-)
1751
1 file changed, 5 insertions(+), 5 deletions(-)
(-)a/source3/smbd/dir.c (-7 / +5 lines)
 Lines 1728-1738   static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1728
		goto fail;
1728
		goto fail;
1729
	}
1729
	}
1730
1730
1731
	if (sconn && !sconn->using_smb2) {
1732
		sconn->searches.dirhandles_open++;
1733
	}
1734
	talloc_set_destructor(dirp, smb_Dir_destructor);
1735
1736
	dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1731
	dirp->dir = SMB_VFS_FDOPENDIR(fsp, mask, attr);
1737
	if (dirp->dir != NULL) {
1732
	if (dirp->dir != NULL) {
1738
		dirp->fsp = fsp;
1733
		dirp->fsp = fsp;
 Lines 1757-1762   static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1757
		goto fail;
1752
		goto fail;
1758
	}
1753
	}
1759
1754
1755
	if (sconn && !sconn->using_smb2) {
1756
		sconn->searches.dirhandles_open++;
1757
	}
1758
	talloc_set_destructor(dirp, smb_Dir_destructor);
1759
1760
	return dirp;
1760
	return dirp;
1761
1761
1762
  fail:
1762
  fail:
1763
- 
1764
FDOPENDIR not supported on system.
1763
FDOPENDIR not supported on system.
1765
--
1766
source3/smbd/dir.c | 15 +++++++--------
1764
source3/smbd/dir.c | 15 +++++++--------
1767
1 file changed, 7 insertions(+), 8 deletions(-)
1765
1 file changed, 7 insertions(+), 8 deletions(-)
(-)a/source3/smbd/dir.c (-10 / +7 lines)
 Lines 1742-1755   static struct smb_Dir *OpenDir_fsp(TALLOC_CTX *mem_ctx, connection_struct *conn, Link Here 
1742
	}
1742
	}
1743
1743
1744
	if (dirp->dir == NULL) {
1744
	if (dirp->dir == NULL) {
1745
		/* FDOPENDIR didn't work. Use OPENDIR instead. */
1745
		/* FDOPENDIR is not supported. Use OPENDIR instead. */
1746
		dirp->dir = SMB_VFS_OPENDIR(conn, dirp->dir_path, mask, attr);
1746
		TALLOC_FREE(dirp);
1747
	}
1747
		return open_dir_safely(mem_ctx,
1748
1748
					conn,
1749
	if (!dirp->dir) {
1749
					fsp->fsp_name->base_name,
1750
		DEBUG(5,("OpenDir_fsp: Can't open %s. %s\n", dirp->dir_path,
1750
					mask,
1751
			 strerror(errno) ));
1751
					attr);
1752
		goto fail;
1753
	}
1752
	}
1754
1753
1755
	if (sconn && !sconn->using_smb2) {
1754
	if (sconn && !sconn->using_smb2) {
1756
- 
1757
O_NOFOLLOW existing.
1755
O_NOFOLLOW existing.
1758
--
1759
source3/smbd/open.c | 6 +-----
1756
source3/smbd/open.c | 6 +-----
1760
1 file changed, 1 insertion(+), 5 deletions(-)
1757
1 file changed, 1 insertion(+), 5 deletions(-)
(-)a/source3/smbd/open.c (-7 / +1 lines)
 Lines 356-363   NTSTATUS fd_open(struct connection_struct *conn, Link Here 
356
	struct smb_filename *smb_fname = fsp->fsp_name;
356
	struct smb_filename *smb_fname = fsp->fsp_name;
357
	NTSTATUS status = NT_STATUS_OK;
357
	NTSTATUS status = NT_STATUS_OK;
358
358
359
#ifdef O_NOFOLLOW
359
	/*
360
	/* 
361
	 * Never follow symlinks on a POSIX client. The
360
	 * Never follow symlinks on a POSIX client. The
362
	 * client should be doing this.
361
	 * client should be doing this.
363
	 */
362
	 */
 Lines 365-376   NTSTATUS fd_open(struct connection_struct *conn, Link Here 
365
	if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) || !lp_follow_symlinks(SNUM(conn))) {
364
	if ((fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) || !lp_follow_symlinks(SNUM(conn))) {
366
		flags |= O_NOFOLLOW;
365
		flags |= O_NOFOLLOW;
367
	}
366
	}
368
#endif
369
367
370
	fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
368
	fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
371
	if (fsp->fh->fd == -1) {
369
	if (fsp->fh->fd == -1) {
372
		int posix_errno = errno;
370
		int posix_errno = errno;
373
#ifdef O_NOFOLLOW
374
#if defined(ENOTSUP) && defined(OSF1)
371
#if defined(ENOTSUP) && defined(OSF1)
375
		/* handle special Tru64 errno */
372
		/* handle special Tru64 errno */
376
		if (errno == ENOTSUP) {
373
		if (errno == ENOTSUP) {
 Lines 387-393   NTSTATUS fd_open(struct connection_struct *conn, Link Here 
387
		if (errno == EMLINK) {
384
		if (errno == EMLINK) {
388
			posix_errno = ELOOP;
385
			posix_errno = ELOOP;
389
		}
386
		}
390
#endif /* O_NOFOLLOW */
391
		status = map_nt_error_from_unix(posix_errno);
387
		status = map_nt_error_from_unix(posix_errno);
392
		if (errno == EMFILE) {
388
		if (errno == EMFILE) {
393
			static time_t last_warned = 0L;
389
			static time_t last_warned = 0L;
394
- 
395
a utility function.
390
a utility function.
396
--
397
source3/smbd/open.c | 43 ++++++++++++++++++++++++++-----------------
391
source3/smbd/open.c | 43 ++++++++++++++++++++++++++-----------------
398
1 file changed, 26 insertions(+), 17 deletions(-)
392
1 file changed, 26 insertions(+), 17 deletions(-)
(-)a/source3/smbd/open.c (-19 / +26 lines)
 Lines 345-350   static NTSTATUS check_base_file_access(struct connection_struct *conn, Link Here 
345
}
345
}
346
346
347
/****************************************************************************
347
/****************************************************************************
348
 Handle differing symlink errno's
349
****************************************************************************/
350
351
static int link_errno_convert(int err)
352
{
353
#if defined(ENOTSUP) && defined(OSF1)
354
	/* handle special Tru64 errno */
355
	if (err == ENOTSUP) {
356
		err = ELOOP;
357
	}
358
#endif /* ENOTSUP */
359
#ifdef EFTYPE
360
	/* fix broken NetBSD errno */
361
	if (err == EFTYPE) {
362
		err = ELOOP;
363
	}
364
#endif /* EFTYPE */
365
	/* fix broken FreeBSD errno */
366
	if (err == EMLINK) {
367
		err = ELOOP;
368
	}
369
	return err;
370
}
371
372
/****************************************************************************
348
 fd support routines - attempt to do a dos_open.
373
 fd support routines - attempt to do a dos_open.
349
****************************************************************************/
374
****************************************************************************/
350
375
 Lines 367-389   NTSTATUS fd_open(struct connection_struct *conn, Link Here 
367
392
368
	fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
393
	fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
369
	if (fsp->fh->fd == -1) {
394
	if (fsp->fh->fd == -1) {
370
		int posix_errno = errno;
395
		int posix_errno = link_errno_convert(errno);
371
#if defined(ENOTSUP) && defined(OSF1)
372
		/* handle special Tru64 errno */
373
		if (errno == ENOTSUP) {
374
			posix_errno = ELOOP;
375
		}
376
#endif /* ENOTSUP */
377
#ifdef EFTYPE
378
		/* fix broken NetBSD errno */
379
		if (errno == EFTYPE) {
380
			posix_errno = ELOOP;
381
		}
382
#endif /* EFTYPE */
383
		/* fix broken FreeBSD errno */
384
		if (errno == EMLINK) {
385
			posix_errno = ELOOP;
386
		}
387
		status = map_nt_error_from_unix(posix_errno);
396
		status = map_nt_error_from_unix(posix_errno);
388
		if (errno == EMFILE) {
397
		if (errno == EMFILE) {
389
			static time_t last_warned = 0L;
398
			static time_t last_warned = 0L;
390
- 
391
open races.
399
open races.
392
--
393
source3/smbd/open.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++
400
source3/smbd/open.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++
394
1 file changed, 237 insertions(+)
401
1 file changed, 237 insertions(+)
(-)a/source3/smbd/open.c (-2 / +237 lines)
 Lines 369-374   static int link_errno_convert(int err) Link Here 
369
	return err;
369
	return err;
370
}
370
}
371
371
372
static int non_widelink_open(struct connection_struct *conn,
373
			const char *conn_rootdir,
374
			files_struct *fsp,
375
			struct smb_filename *smb_fname,
376
			int flags,
377
			mode_t mode,
378
			unsigned int link_depth);
379
380
/****************************************************************************
381
 Follow a symlink in userspace.
382
****************************************************************************/
383
384
static int process_symlink_open(struct connection_struct *conn,
385
			const char *conn_rootdir,
386
			files_struct *fsp,
387
			struct smb_filename *smb_fname,
388
			int flags,
389
			mode_t mode,
390
			unsigned int link_depth)
391
{
392
	int fd = -1;
393
	char *link_target = NULL;
394
	int link_len = -1;
395
	char *oldwd = NULL;
396
	size_t rootdir_len = 0;
397
	char *resolved_name = NULL;
398
	bool matched = false;
399
	int saved_errno = 0;
400
401
	/*
402
	 * Ensure we don't get stuck in a symlink loop.
403
	 */
404
	link_depth++;
405
	if (link_depth >= 20) {
406
		errno = ELOOP;
407
		goto out;
408
	}
409
410
	/* Allocate space for the link target. */
411
	link_target = talloc_array(talloc_tos(), char, PATH_MAX);
412
	if (link_target == NULL) {
413
		errno = ENOMEM;
414
		goto out;
415
	}
416
417
	/* Read the link target. */
418
	link_len = SMB_VFS_READLINK(conn,
419
				smb_fname->base_name,
420
				link_target,
421
				PATH_MAX - 1);
422
	if (link_len == -1) {
423
		goto out;
424
	}
425
426
	/* Ensure it's at least null terminated. */
427
	link_target[link_len] = '\0';
428
429
	/* Convert to an absolute path. */
430
	resolved_name = SMB_VFS_REALPATH(conn, link_target);
431
	if (resolved_name == NULL) {
432
		goto out;
433
	}
434
435
	/*
436
	 * We know conn_rootdir starts with '/' and
437
	 * does not end in '/'. FIXME ! Should we
438
	 * smb_assert this ?
439
	 */
440
	rootdir_len = strlen(conn_rootdir);
441
442
	matched = (strncmp(conn_rootdir, resolved_name, rootdir_len) == 0);
443
	if (!matched) {
444
		errno = EACCES;
445
		goto out;
446
	}
447
448
	/*
449
	 * Turn into a path relative to the share root.
450
	 */
451
	if (resolved_name[rootdir_len] == '\0') {
452
		/* Link to the root of the share. */
453
		smb_fname->base_name = talloc_strdup(talloc_tos(), ".");
454
		if (smb_fname->base_name == NULL) {
455
			errno = ENOMEM;
456
			goto out;
457
		}
458
	} else if (resolved_name[rootdir_len] == '/') {
459
		smb_fname->base_name = &resolved_name[rootdir_len+1];
460
	} else {
461
		errno = EACCES;
462
		goto out;
463
	}
464
465
	oldwd = vfs_GetWd(talloc_tos(), conn);
466
	if (oldwd == NULL) {
467
		goto out;
468
	}
469
470
	/* Ensure we operate from the root of the share. */
471
	if (vfs_ChDir(conn, conn_rootdir) == -1) {
472
		goto out;
473
	}
474
475
	/* And do it all again.. */
476
	fd = non_widelink_open(conn,
477
				conn_rootdir,
478
				fsp,
479
				smb_fname,
480
				flags,
481
				mode,
482
				link_depth);
483
	if (fd == -1) {
484
		saved_errno = errno;
485
	}
486
487
  out:
488
489
	SAFE_FREE(resolved_name);
490
	TALLOC_FREE(link_target);
491
	if (oldwd != NULL) {
492
		int ret = vfs_ChDir(conn, oldwd);
493
		if (ret == -1) {
494
			smb_panic("unable to get back to old directory\n");
495
		}
496
		TALLOC_FREE(oldwd);
497
	}
498
	if (saved_errno != 0) {
499
		errno = saved_errno;
500
	}
501
	return fd;
502
}
503
504
/****************************************************************************
505
 Non-widelink open.
506
****************************************************************************/
507
508
static int non_widelink_open(struct connection_struct *conn,
509
			const char *conn_rootdir,
510
			files_struct *fsp,
511
			struct smb_filename *smb_fname,
512
			int flags,
513
			mode_t mode,
514
			unsigned int link_depth)
515
{
516
	NTSTATUS status;
517
	int fd = -1;
518
	struct smb_filename *smb_fname_rel = NULL;
519
	int saved_errno = 0;
520
	char *oldwd = NULL;
521
	char *parent_dir = NULL;
522
	const char *final_component = NULL;
523
524
	if (!parent_dirname(talloc_tos(),
525
			smb_fname->base_name,
526
			&parent_dir,
527
			&final_component)) {
528
		goto out;
529
	}
530
531
	oldwd = vfs_GetWd(talloc_tos(), conn);
532
	if (oldwd == NULL) {
533
		goto out;
534
	}
535
536
	/* Pin parent directory in place. */
537
	if (vfs_ChDir(conn, parent_dir) == -1) {
538
		goto out;
539
	}
540
541
	/* Ensure the relative path is below the share. */
542
	status = check_reduced_name(conn, final_component);
543
	if (!NT_STATUS_IS_OK(status)) {
544
		saved_errno = map_errno_from_nt_status(status);
545
		goto out;
546
	}
547
548
	smb_fname_rel = synthetic_smb_fname(talloc_tos(),
549
				final_component,
550
				smb_fname->stream_name,
551
				&smb_fname->st);
552
553
	flags |= O_NOFOLLOW;
554
555
	{
556
		struct smb_filename *tmp_name = fsp->fsp_name;
557
		fsp->fsp_name = smb_fname_rel;
558
		fd = SMB_VFS_OPEN(conn, smb_fname_rel, fsp, flags, mode);
559
		fsp->fsp_name = tmp_name;
560
	}
561
562
	if (fd == -1) {
563
		saved_errno = link_errno_convert(errno);
564
		if (saved_errno == ELOOP) {
565
			if (fsp->posix_flags & FSP_POSIX_FLAGS_OPEN) {
566
				/* Never follow symlinks on posix open. */
567
				goto out;
568
			}
569
			if (!lp_follow_symlinks(SNUM(conn))) {
570
				/* Explicitly no symlinks. */
571
				goto out;
572
			}
573
			/*
574
			 * We have a symlink. Follow in userspace
575
			 * to ensure it's under the share definition.
576
			 */
577
			fd = process_symlink_open(conn,
578
					conn_rootdir,
579
					fsp,
580
					smb_fname_rel,
581
					flags,
582
					mode,
583
					link_depth);
584
			if (fd == -1) {
585
				saved_errno =
586
					link_errno_convert(errno);
587
			}
588
		}
589
	}
590
591
  out:
592
593
	TALLOC_FREE(parent_dir);
594
	TALLOC_FREE(smb_fname_rel);
595
596
	if (oldwd != NULL) {
597
		int ret = vfs_ChDir(conn, oldwd);
598
		if (ret == -1) {
599
			smb_panic("unable to get back to old directory\n");
600
		}
601
		TALLOC_FREE(oldwd);
602
	}
603
	if (saved_errno != 0) {
604
		errno = saved_errno;
605
	}
606
	return fd;
607
}
608
372
/****************************************************************************
609
/****************************************************************************
373
 fd support routines - attempt to do a dos_open.
610
 fd support routines - attempt to do a dos_open.
374
****************************************************************************/
611
****************************************************************************/
375
- 
376
--
377
source3/smbd/open.c | 23 ++++++++++++++++++++++-
612
source3/smbd/open.c | 23 ++++++++++++++++++++++-
378
1 file changed, 22 insertions(+), 1 deletion(-)
613
1 file changed, 22 insertions(+), 1 deletion(-)
(-)a/source3/smbd/open.c (-2 / +22 lines)
 Lines 627-633   NTSTATUS fd_open(struct connection_struct *conn, Link Here 
627
		flags |= O_NOFOLLOW;
627
		flags |= O_NOFOLLOW;
628
	}
628
	}
629
629
630
	fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
630
	/* Ensure path is below share definition. */
631
	if (!lp_widelinks(SNUM(conn))) {
632
		const char *conn_rootdir = SMB_VFS_CONNECTPATH(conn,
633
						smb_fname->base_name);
634
		if (conn_rootdir == NULL) {
635
			return NT_STATUS_NO_MEMORY;
636
		}
637
		/*
638
		 * Only follow symlinks within a share
639
		 * definition.
640
		 */
641
		fsp->fh->fd = non_widelink_open(conn,
642
					conn_rootdir,
643
					fsp,
644
					smb_fname,
645
					flags,
646
					mode,
647
					0);
648
	} else {
649
		fsp->fh->fd = SMB_VFS_OPEN(conn, smb_fname, fsp, flags, mode);
650
	}
651
631
	if (fsp->fh->fd == -1) {
652
	if (fsp->fh->fd == -1) {
632
		int posix_errno = link_errno_convert(errno);
653
		int posix_errno = link_errno_convert(errno);
633
		status = map_nt_error_from_unix(posix_errno);
654
		status = map_nt_error_from_unix(posix_errno);
634
- 

Return to bug 43679