2007-09-13 01:48:20 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1996-05-04 11:50:46 +04:00
Directory handling routines
1998-01-22 16:27:43 +03:00
Copyright ( C ) Andrew Tridgell 1992 - 1998
2007-09-13 01:48:20 +04:00
Copyright ( C ) Jeremy Allison 2007
1996-05-04 11:50:46 +04:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
2007-07-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1996-05-04 11:50:46 +04:00
( at your option ) any later version .
2007-09-13 01:48:20 +04:00
1996-05-04 11:50:46 +04:00
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
2007-09-13 01:48:20 +04:00
1996-05-04 11:50:46 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1996-05-04 11:50:46 +04:00
*/
# include "includes.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2020-10-28 14:09:39 +03:00
# include "locking/share_mode_lock.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
2010-10-12 08:27:50 +04:00
# include "libcli/security/security.h"
2011-07-07 15:04:31 +04:00
# include "lib/util/bitmap.h"
2014-07-17 14:58:34 +04:00
# include "../lib/util/memcache.h"
2014-09-25 03:30:33 +04:00
# include "../librpc/gen_ndr/open_files.h"
2020-08-07 21:17:34 +03:00
# include "lib/util/string_wrappers.h"
2023-06-22 16:12:25 +03:00
# include "libcli/smb/reparse_symlink.h"
1996-05-04 11:50:46 +04:00
/*
This module implements directory related functions for Samba .
*/
2005-07-22 00:24:21 +04:00
/* "Special" directory offsets. */
# define END_OF_DIRECTORY_OFFSET ((long)-1)
# define START_OF_DIRECTORY_OFFSET ((long)0)
# define DOT_DOT_DIRECTORY_OFFSET ((long)0x80000000)
2005-02-01 03:28:20 +03:00
/* Make directory handle internals available. */
struct smb_Dir {
connection_struct * conn ;
2012-03-28 06:22:03 +04:00
DIR * dir ;
2016-02-27 01:59:51 +03:00
struct smb_filename * dir_smb_fname ;
2005-06-11 03:13:25 +04:00
unsigned int file_number ;
2021-10-16 02:48:03 +03:00
bool case_sensitive ;
2013-04-11 03:21:39 +04:00
files_struct * fsp ; /* Back pointer to containing fsp, only
set from OpenDir_fsp ( ) . */
2005-02-01 03:28:20 +03:00
} ;
struct dptr_struct {
struct dptr_struct * next , * prev ;
1999-12-13 16:27:58 +03:00
int dnum ;
2005-02-01 03:28:20 +03:00
struct connection_struct * conn ;
struct smb_Dir * dir_hnd ;
char * wcard ;
2015-05-03 07:01:14 +03:00
uint32_t attr ;
2007-10-19 04:40:25 +04:00
bool has_wild ; /* Set to true if the wcard entry has MS wildcard characters in it. */
bool did_stat ; /* Optimisation for non-wcard searches. */
2012-02-29 23:42:21 +04:00
bool priv ; /* Directory handle opened with privilege. */
2014-01-12 03:45:48 +04:00
uint32_t counter ;
2023-05-27 14:20:56 +03:00
2023-06-09 16:22:31 +03:00
char * last_name_sent ; /* for name-based trans2 resume */
2023-05-27 14:20:56 +03:00
struct {
char * fname ;
struct smb_filename * smb_fname ;
uint32_t mode ;
} overflow ;
2005-02-01 03:28:20 +03:00
} ;
1996-05-04 11:50:46 +04:00
2022-02-21 19:12:05 +03:00
static NTSTATUS OpenDir_fsp (
TALLOC_CTX * mem_ctx ,
connection_struct * conn ,
files_struct * fsp ,
const char * mask ,
uint32_t attr ,
struct smb_Dir * * _dir_hnd ) ;
1996-05-04 11:50:46 +04:00
2019-07-17 19:40:04 +03:00
static int smb_Dir_destructor ( struct smb_Dir * dir_hnd ) ;
2019-07-17 18:56:49 +03:00
1999-12-13 16:27:58 +03:00
# define INVALID_DPTR_KEY (-3)
1996-05-04 11:50:46 +04:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
Initialise the dir bitmap .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2009-08-06 14:15:51 +04:00
bool init_dptrs ( struct smbd_server_connection * sconn )
1996-05-04 11:50:46 +04:00
{
2011-03-18 02:16:54 +03:00
if ( sconn - > searches . dptr_bmap ) {
2009-08-06 14:15:51 +04:00
return true ;
}
1999-12-13 16:27:58 +03:00
2011-03-18 02:16:54 +03:00
sconn - > searches . dptr_bmap = bitmap_talloc (
2010-03-28 16:16:55 +04:00
sconn , MAX_DIRECTORY_HANDLES ) ;
2009-08-06 14:15:51 +04:00
2011-03-18 02:16:54 +03:00
if ( sconn - > searches . dptr_bmap = = NULL ) {
2009-08-06 14:15:51 +04:00
return false ;
}
1999-12-13 16:27:58 +03:00
2009-08-06 14:15:51 +04:00
return true ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2005-02-01 03:28:20 +03:00
Get the struct dptr_struct for a dir index .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2009-08-06 14:15:51 +04:00
static struct dptr_struct * dptr_get ( struct smbd_server_connection * sconn ,
2019-07-09 01:20:42 +03:00
int key )
1996-05-04 11:50:46 +04:00
{
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr ;
2003-01-03 21:50:13 +03:00
2018-03-05 14:55:23 +03:00
for ( dptr = sconn - > searches . dirptrs ; dptr ! = NULL ; dptr = dptr - > next ) {
if ( dptr - > dnum ! = key ) {
continue ;
}
DLIST_PROMOTE ( sconn - > searches . dirptrs , dptr ) ;
return dptr ;
2003-01-03 21:50:13 +03:00
}
return ( NULL ) ;
1996-05-04 11:50:46 +04:00
}
1999-12-13 16:27:58 +03:00
/****************************************************************************
Get the dir path for a dir index .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-02-25 05:12:52 +04:00
const char * dptr_path ( struct smbd_server_connection * sconn , int key )
1996-05-04 11:50:46 +04:00
{
2019-07-09 01:20:42 +03:00
struct dptr_struct * dptr = dptr_get ( sconn , key ) ;
2003-01-03 21:50:13 +03:00
if ( dptr )
2023-02-02 14:52:32 +03:00
return ( dptr - > dir_hnd - > dir_smb_fname - > base_name ) ;
2003-01-03 21:50:13 +03:00
return ( NULL ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2005-02-01 03:28:20 +03:00
Get the dir wcard for a dir index .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2012-02-25 05:12:52 +04:00
const char * dptr_wcard ( struct smbd_server_connection * sconn , int key )
1996-05-04 11:50:46 +04:00
{
2019-07-09 01:20:42 +03:00
struct dptr_struct * dptr = dptr_get ( sconn , key ) ;
2003-01-03 21:50:13 +03:00
if ( dptr )
return ( dptr - > wcard ) ;
return ( NULL ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
2005-02-01 03:28:20 +03:00
Get the dir attrib for a dir index .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2015-05-03 07:01:14 +03:00
uint16_t dptr_attr ( struct smbd_server_connection * sconn , int key )
1996-05-04 11:50:46 +04:00
{
2019-07-09 01:20:42 +03:00
struct dptr_struct * dptr = dptr_get ( sconn , key ) ;
2005-02-01 03:28:20 +03:00
if ( dptr )
return ( dptr - > attr ) ;
return ( 0 ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
1999-12-13 16:27:58 +03:00
Close all dptrs for a cnum .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
1998-08-14 21:38:29 +04:00
void dptr_closecnum ( connection_struct * conn )
1996-05-04 11:50:46 +04:00
{
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr , * next ;
2009-08-06 14:15:51 +04:00
struct smbd_server_connection * sconn = conn - > sconn ;
if ( sconn = = NULL ) {
return ;
}
2011-03-18 02:16:54 +03:00
for ( dptr = sconn - > searches . dirptrs ; dptr ; dptr = next ) {
2003-01-03 21:50:13 +03:00
next = dptr - > next ;
2009-08-06 14:15:51 +04:00
if ( dptr - > conn = = conn ) {
2022-02-01 19:47:29 +03:00
/*
* Need to make a copy , " dptr " will be gone
* after close_file_free ( ) returns
*/
struct files_struct * fsp = dptr - > dir_hnd - > fsp ;
close_file_free ( NULL , & fsp , NORMAL_CLOSE ) ;
2009-08-06 14:15:51 +04:00
}
2003-01-03 21:50:13 +03:00
}
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
1999-12-13 16:27:58 +03:00
Create a new dir ptr . If the flag old_handle is true then we must allocate
from the bitmap range 0 - 255 as old SMBsearch directory handles are only
one byte long . If old_handle is false we allocate from the range
256 - MAX_DIRECTORY_HANDLES . We bias the number we return by 1 to ensure
2005-02-01 03:28:20 +03:00
a directory handle is never zero .
2005-08-13 03:45:16 +04:00
wcard must not be zero .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2012-03-01 04:05:50 +04:00
NTSTATUS dptr_create ( connection_struct * conn ,
struct smb_request * req ,
files_struct * fsp ,
2016-02-27 03:35:17 +03:00
bool old_handle ,
const char * wcard ,
uint32_t attr ,
struct dptr_struct * * dptr_ret )
1996-05-04 11:50:46 +04:00
{
2009-08-06 14:15:51 +04:00
struct smbd_server_connection * sconn = conn - > sconn ;
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr = NULL ;
2022-02-21 19:09:36 +03:00
struct smb_Dir * dir_hnd = NULL ;
2022-02-21 19:12:05 +03:00
NTSTATUS status ;
2005-02-01 03:28:20 +03:00
2019-08-04 10:13:34 +03:00
DBG_INFO ( " dir=%s \n " , fsp_str_dbg ( fsp ) ) ;
1996-05-04 11:50:46 +04:00
2009-08-06 14:15:51 +04:00
if ( sconn = = NULL ) {
DEBUG ( 0 , ( " dptr_create: called with fake connection_struct \n " ) ) ;
return NT_STATUS_INTERNAL_ERROR ;
}
2005-08-13 03:45:16 +04:00
if ( ! wcard ) {
2007-01-17 05:09:37 +03:00
return NT_STATUS_INVALID_PARAMETER ;
2005-08-13 03:45:16 +04:00
}
2019-07-17 21:21:12 +03:00
if ( ! ( fsp - > access_mask & SEC_DIR_LIST ) ) {
DBG_INFO ( " dptr_create: directory %s "
" not open for LIST access \n " ,
2019-08-04 10:13:34 +03:00
fsp_str_dbg ( fsp ) ) ;
2019-07-17 21:21:12 +03:00
return NT_STATUS_ACCESS_DENIED ;
2007-01-17 05:09:37 +03:00
}
2022-02-21 19:12:05 +03:00
status = OpenDir_fsp ( NULL , conn , fsp , wcard , attr , & dir_hnd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2005-02-01 03:28:20 +03:00
}
2015-02-23 14:04:58 +03:00
dptr = talloc_zero ( NULL , struct dptr_struct ) ;
2003-01-03 21:50:13 +03:00
if ( ! dptr ) {
2012-02-25 05:16:08 +04:00
DEBUG ( 0 , ( " talloc fail in dptr_create. \n " ) ) ;
2008-01-12 19:08:04 +03:00
TALLOC_FREE ( dir_hnd ) ;
2007-01-17 05:09:37 +03:00
return NT_STATUS_NO_MEMORY ;
2003-01-03 21:50:13 +03:00
}
1999-12-13 16:27:58 +03:00
2011-11-09 18:59:22 +04:00
dptr - > conn = conn ;
dptr - > dir_hnd = dir_hnd ;
2012-02-25 05:16:08 +04:00
dptr - > wcard = talloc_strdup ( dptr , wcard ) ;
2011-11-09 18:59:22 +04:00
if ( ! dptr - > wcard ) {
2012-02-25 05:16:08 +04:00
TALLOC_FREE ( dptr ) ;
2011-11-09 18:59:22 +04:00
TALLOC_FREE ( dir_hnd ) ;
return NT_STATUS_NO_MEMORY ;
}
2023-02-02 14:19:46 +03:00
if ( ( req ! = NULL & & req - > posix_pathnames ) | | ISDOT ( wcard ) ) {
2011-11-09 18:59:22 +04:00
dptr - > has_wild = True ;
} else {
2020-09-29 21:58:54 +03:00
dptr - > has_wild = ms_has_wild ( dptr - > wcard ) ;
2011-11-09 18:59:22 +04:00
}
dptr - > attr = attr ;
2011-11-09 19:04:09 +04:00
if ( sconn - > using_smb2 ) {
goto done ;
}
2003-01-03 21:50:13 +03:00
if ( old_handle ) {
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
/*
* This is an old - style SMBsearch request . Ensure the
* value we return will fit in the range 1 - 255.
*/
1999-12-13 16:27:58 +03:00
2011-03-18 02:16:54 +03:00
dptr - > dnum = bitmap_find ( sconn - > searches . dptr_bmap , 0 ) ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
if ( dptr - > dnum = = - 1 | | dptr - > dnum > 254 ) {
2019-07-09 01:23:57 +03:00
DBG_ERR ( " returned %d: Error - all old "
" dirptrs in use ? \n " ,
dptr - > dnum ) ;
TALLOC_FREE ( dptr ) ;
TALLOC_FREE ( dir_hnd ) ;
return NT_STATUS_TOO_MANY_OPENED_FILES ;
2003-01-03 21:50:13 +03:00
}
} else {
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
/*
* This is a new - style trans2 request . Allocate from
* a range that will return 256 - MAX_DIRECTORY_HANDLES .
*/
1999-12-13 16:27:58 +03:00
2011-03-18 02:16:54 +03:00
dptr - > dnum = bitmap_find ( sconn - > searches . dptr_bmap , 255 ) ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
if ( dptr - > dnum = = - 1 | | dptr - > dnum < 255 ) {
2019-07-09 01:26:59 +03:00
DBG_ERR ( " returned %d: Error - all new "
" dirptrs in use ? \n " ,
dptr - > dnum ) ;
TALLOC_FREE ( dptr ) ;
TALLOC_FREE ( dir_hnd ) ;
return NT_STATUS_TOO_MANY_OPENED_FILES ;
2003-01-03 21:50:13 +03:00
}
}
1996-05-04 11:50:46 +04:00
2011-03-18 02:16:54 +03:00
bitmap_set ( sconn - > searches . dptr_bmap , dptr - > dnum ) ;
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
dptr - > dnum + = 1 ; /* Always bias the dnum by one - no zero dnums allowed. */
1996-05-04 11:50:46 +04:00
2011-03-18 02:16:54 +03:00
DLIST_ADD ( sconn - > searches . dirptrs , dptr ) ;
1996-05-04 11:50:46 +04:00
2011-11-09 19:04:09 +04:00
done :
2023-02-06 23:40:38 +03:00
DBG_INFO ( " creating new dirptr [%d] for path [%s] \n " ,
dptr - > dnum , fsp_str_dbg ( fsp ) ) ;
1996-05-04 11:50:46 +04:00
2007-01-18 09:19:24 +03:00
* dptr_ret = dptr ;
2005-02-01 03:28:20 +03:00
2007-01-17 05:09:37 +03:00
return NT_STATUS_OK ;
1996-05-04 11:50:46 +04:00
}
2005-02-01 03:28:20 +03:00
/****************************************************************************
Wrapper functions to access the lower level directory handles .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-02-09 02:05:00 +03:00
void dptr_CloseDir ( files_struct * fsp )
2005-02-01 03:28:20 +03:00
{
2019-08-14 09:37:00 +03:00
struct smbd_server_connection * sconn = NULL ;
2019-08-04 10:21:55 +03:00
2019-08-04 10:15:47 +03:00
if ( fsp - > dptr = = NULL ) {
return ;
2011-02-09 02:05:00 +03:00
}
2019-08-14 09:37:00 +03:00
sconn = fsp - > dptr - > conn - > sconn ;
2019-08-04 10:15:47 +03:00
/*
* The destructor for the struct smb_Dir ( fsp - > dptr - > dir_hnd )
* now handles all resource deallocation .
*/
2019-08-04 10:21:55 +03:00
DBG_INFO ( " closing dptr key %d \n " , fsp - > dptr - > dnum ) ;
if ( sconn ! = NULL & & ! sconn - > using_smb2 ) {
DLIST_REMOVE ( sconn - > searches . dirptrs , fsp - > dptr ) ;
/*
* Free the dnum in the bitmap . Remember the dnum value is
* always biased by one with respect to the bitmap .
*/
if ( ! bitmap_query ( sconn - > searches . dptr_bmap ,
fsp - > dptr - > dnum - 1 ) )
{
DBG_ERR ( " closing dnum = %d and bitmap not set ! \n " ,
fsp - > dptr - > dnum ) ;
}
bitmap_clear ( sconn - > searches . dptr_bmap , fsp - > dptr - > dnum - 1 ) ;
}
TALLOC_FREE ( fsp - > dptr - > dir_hnd ) ;
TALLOC_FREE ( fsp - > dptr ) ;
2005-02-01 03:28:20 +03:00
}
2023-06-08 12:59:35 +03:00
void dptr_RewindDir ( struct dptr_struct * dptr )
{
2023-06-10 16:29:35 +03:00
RewindDir ( dptr - > dir_hnd ) ;
2023-06-13 16:42:19 +03:00
dptr - > did_stat = false ;
2023-05-27 14:20:56 +03:00
TALLOC_FREE ( dptr - > overflow . fname ) ;
TALLOC_FREE ( dptr - > overflow . smb_fname ) ;
2023-06-08 12:59:35 +03:00
}
2023-06-07 18:10:51 +03:00
unsigned int dptr_FileNumber ( struct dptr_struct * dptr )
{
return dptr - > dir_hnd - > file_number ;
}
2007-10-19 04:40:25 +04:00
bool dptr_has_wild ( struct dptr_struct * dptr )
2006-09-15 13:06:36 +04:00
{
return dptr - > has_wild ;
}
2007-01-18 09:19:24 +03:00
int dptr_dnum ( struct dptr_struct * dptr )
{
return dptr - > dnum ;
}
2012-02-29 23:42:21 +04:00
bool dptr_get_priv ( struct dptr_struct * dptr )
{
return dptr - > priv ;
}
void dptr_set_priv ( struct dptr_struct * dptr )
{
dptr - > priv = true ;
}
2021-11-08 22:21:03 +03:00
bool dptr_case_sensitive ( struct dptr_struct * dptr )
{
return dptr - > dir_hnd - > case_sensitive ;
}
2005-02-01 21:33:50 +03:00
/****************************************************************************
Return the next visible file name , skipping veto ' d and invisible files .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2023-06-20 13:19:15 +03:00
char * dptr_ReadDirName ( TALLOC_CTX * ctx , struct dptr_struct * dptr )
2005-02-01 21:33:50 +03:00
{
2023-06-20 13:19:15 +03:00
struct stat_ex st = {
. st_ex_nlink = 0 ,
} ;
2023-06-13 16:42:19 +03:00
struct smb_Dir * dir_hnd = dptr - > dir_hnd ;
struct files_struct * dir_fsp = dir_hnd - > fsp ;
struct smb_filename * dir_name = dir_fsp - > fsp_name ;
2009-11-15 12:46:23 +03:00
struct smb_filename smb_fname_base ;
2023-06-13 16:42:19 +03:00
bool retry_scanning = false ;
int ret ;
int flags = 0 ;
2009-05-02 04:28:38 +04:00
2023-06-13 16:42:19 +03:00
if ( dptr - > has_wild ) {
const char * name_temp = NULL ;
char * talloced = NULL ;
2023-06-20 13:25:45 +03:00
name_temp = ReadDirName ( dir_hnd , & talloced ) ;
2009-11-16 11:49:23 +03:00
if ( name_temp = = NULL ) {
return NULL ;
}
if ( talloced ! = NULL ) {
return talloc_move ( ctx , & talloced ) ;
}
return talloc_strdup ( ctx , name_temp ) ;
2005-02-01 21:33:50 +03:00
}
2023-06-13 16:42:19 +03:00
if ( dptr - > did_stat ) {
/*
* No wildcard , this is not a real directory traverse
* but a " stat " call behind a query_directory . We ' ve
* been here , nothing else to look at .
*/
2005-03-03 05:04:36 +03:00
return NULL ;
}
2009-01-23 07:18:56 +03:00
dptr - > did_stat = true ;
2009-06-23 02:26:56 +04:00
/* Create an smb_filename with stream_name == NULL. */
2023-06-13 16:42:19 +03:00
smb_fname_base = ( struct smb_filename ) {
. base_name = dptr - > wcard ,
. flags = dir_name - > flags ,
. twrp = dir_name - > twrp ,
2020-05-01 17:55:58 +03:00
} ;
2009-06-23 02:26:56 +04:00
2023-06-13 16:42:19 +03:00
if ( dir_name - > flags & SMB_FILENAME_POSIX_PATH ) {
flags | = AT_SYMLINK_NOFOLLOW ;
}
2023-06-20 13:19:15 +03:00
ret = SMB_VFS_FSTATAT ( dptr - > conn , dir_fsp , & smb_fname_base , & st , flags ) ;
2023-06-13 16:42:19 +03:00
if ( ret = = 0 ) {
return talloc_strdup ( ctx , dptr - > wcard ) ;
2009-01-23 07:18:56 +03:00
}
2006-09-15 13:06:36 +04:00
2023-06-13 16:42:19 +03:00
/*
* If we get any other error than ENOENT or ENOTDIR
* then the file exists , we just can ' t stat it .
2009-01-23 07:18:56 +03:00
*/
2023-06-13 16:42:19 +03:00
if ( errno ! = ENOENT & & errno ! = ENOTDIR ) {
return talloc_strdup ( ctx , dptr - > wcard ) ;
2009-01-23 07:18:56 +03:00
}
2007-09-13 01:48:20 +04:00
2009-05-02 04:28:38 +04:00
/*
2023-06-13 16:42:19 +03:00
* A scan will find the long version of a mangled name as
* wildcard .
*/
retry_scanning | = mangle_is_mangled ( dptr - > wcard , dptr - > conn - > params ) ;
/*
* Also retry scanning if the client requested case
* insensitive semantics and the file system does not provide
* it .
2009-05-02 04:28:38 +04:00
*/
2023-06-13 16:42:19 +03:00
retry_scanning | =
( ! dir_hnd - > case_sensitive & &
( dptr - > conn - > fs_capabilities & FILE_CASE_SENSITIVE_SEARCH ) ) ;
if ( retry_scanning ) {
char * found_name = NULL ;
NTSTATUS status ;
status = get_real_filename_at ( dir_fsp ,
2022-03-15 14:45:48 +03:00
dptr - > wcard ,
ctx ,
& found_name ) ;
2023-06-13 16:42:19 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
return found_name ;
}
2009-05-02 04:28:38 +04:00
}
2023-06-13 16:42:19 +03:00
return NULL ;
2005-02-01 21:33:50 +03:00
}
2021-01-22 14:46:04 +03:00
struct files_struct * dir_hnd_fetch_fsp ( struct smb_Dir * dir_hnd )
{
return dir_hnd - > fsp ;
}
2019-07-17 23:20:08 +03:00
/****************************************************************************
Fetch the fsp associated with the dptr_num .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
files_struct * dptr_fetch_lanman2_fsp ( struct smbd_server_connection * sconn ,
int dptr_num )
{
2019-07-17 23:28:53 +03:00
struct dptr_struct * dptr = dptr_get ( sconn , dptr_num ) ;
2019-07-17 23:20:08 +03:00
if ( dptr = = NULL ) {
return NULL ;
}
2019-07-17 23:28:53 +03:00
DBG_NOTICE ( " fetching dirptr %d for path %s \n " ,
2023-02-02 14:52:32 +03:00
dptr_num ,
dptr - > dir_hnd - > dir_smb_fname - > base_name ) ;
2019-07-17 23:20:08 +03:00
return dptr - > dir_hnd - > fsp ;
}
2009-08-06 22:53:13 +04:00
bool smbd_dirptr_get_entry ( TALLOC_CTX * ctx ,
struct dptr_struct * dirptr ,
const char * mask ,
uint32_t dirtype ,
bool dont_descend ,
bool ask_sharemode ,
2020-11-12 12:00:57 +03:00
bool get_dosmode_in ,
2009-08-06 22:53:13 +04:00
bool ( * match_fn ) ( TALLOC_CTX * ctx ,
void * private_data ,
const char * dname ,
const char * mask ,
char * * _fname ) ,
bool ( * mode_fn ) ( TALLOC_CTX * ctx ,
void * private_data ,
2021-07-13 02:40:08 +03:00
struct files_struct * dirfsp ,
2009-08-06 22:53:13 +04:00
struct smb_filename * smb_fname ,
2018-03-15 18:48:38 +03:00
bool get_dosmode ,
2009-08-06 22:53:13 +04:00
uint32_t * _mode ) ,
void * private_data ,
char * * _fname ,
struct smb_filename * * _smb_fname ,
2023-06-09 16:05:07 +03:00
uint32_t * _mode )
2009-08-06 22:53:13 +04:00
{
connection_struct * conn = dirptr - > conn ;
2023-06-09 10:59:36 +03:00
struct smb_Dir * dir_hnd = dirptr - > dir_hnd ;
2023-06-22 12:33:05 +03:00
struct smb_filename * dir_fname = dir_hnd - > dir_smb_fname ;
2023-06-22 16:12:25 +03:00
bool posix = ( dir_fname - > flags & SMB_FILENAME_POSIX_PATH ) ;
2023-06-22 12:33:05 +03:00
const char * dpath = dir_fname - > base_name ;
2020-11-12 12:00:57 +03:00
NTSTATUS status ;
2009-08-06 22:53:13 +04:00
* _smb_fname = NULL ;
* _mode = 0 ;
2023-05-27 14:20:56 +03:00
if ( dirptr - > overflow . smb_fname ! = NULL ) {
* _fname = talloc_move ( ctx , & dirptr - > overflow . fname ) ;
* _smb_fname = talloc_move ( ctx , & dirptr - > overflow . smb_fname ) ;
* _mode = dirptr - > overflow . mode ;
return true ;
}
2023-06-21 18:48:24 +03:00
if ( dont_descend & & ( dptr_FileNumber ( dirptr ) > = 2 ) ) {
/*
* . and . . were returned first , we ' re done showing
* the directory as empty .
*/
return false ;
}
2009-08-06 22:53:13 +04:00
while ( true ) {
char * dname = NULL ;
char * fname = NULL ;
2020-11-12 12:00:57 +03:00
struct smb_filename * smb_fname = NULL ;
2023-06-22 16:12:25 +03:00
struct open_symlink_err * symlink_err = NULL ;
2009-08-06 22:53:13 +04:00
uint32_t mode = 0 ;
2020-11-12 12:00:57 +03:00
bool get_dosmode = get_dosmode_in ;
2009-08-06 22:53:13 +04:00
bool ok ;
2023-06-20 13:19:15 +03:00
dname = dptr_ReadDirName ( ctx , dirptr ) ;
2009-08-06 22:53:13 +04:00
2023-06-15 16:41:35 +03:00
DBG_DEBUG ( " dir [%s] dirptr [%p] offset [%u] => "
2023-06-09 10:59:36 +03:00
" dname [%s] \n " ,
2023-06-22 12:33:05 +03:00
smb_fname_str_dbg ( dir_fname ) ,
2023-06-15 16:41:35 +03:00
dirptr ,
dir_hnd - > file_number ,
2023-06-09 10:59:36 +03:00
dname ? dname : " (finished) " ) ;
2009-08-06 22:53:13 +04:00
if ( dname = = NULL ) {
return false ;
}
2021-06-04 21:20:08 +03:00
if ( IS_VETO_PATH ( conn , dname ) ) {
TALLOC_FREE ( dname ) ;
continue ;
}
2009-08-06 22:53:13 +04:00
/*
* fname may get mangled , dname is never mangled .
* Whenever we ' re accessing the filesystem we use
* pathreal which is composed from dname .
*/
ok = match_fn ( ctx , private_data , dname , mask , & fname ) ;
if ( ! ok ) {
TALLOC_FREE ( dname ) ;
continue ;
}
2023-06-22 16:12:25 +03:00
if ( ISDOT ( dname ) | | ISDOTDOT ( dname ) ) {
2013-03-22 01:00:06 +04:00
2023-06-22 16:12:25 +03:00
const char * dotname = dname ;
2009-08-06 22:53:13 +04:00
2023-06-22 16:12:25 +03:00
if ( ISDOTDOT ( dname ) & & ISDOT ( dpath ) ) {
/*
* Handle " .. " in toplevel like " . " to not
* leak info from outside the share .
*/
dotname = " . " ;
}
2021-02-01 14:04:49 +03:00
2023-06-22 16:12:25 +03:00
smb_fname = synthetic_smb_fname ( talloc_tos ( ) ,
dotname ,
NULL ,
NULL ,
dir_fname - > twrp ,
dir_fname - > flags ) ;
if ( smb_fname = = NULL ) {
TALLOC_FREE ( dname ) ;
return false ;
}
2021-02-01 14:04:49 +03:00
2023-06-22 16:12:25 +03:00
status = openat_pathref_fsp ( dir_hnd - > fsp , smb_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_INFO ( " Could not open \" .. \" : %s \n " ,
nt_errstr ( status ) ) ;
TALLOC_FREE ( smb_fname ) ;
TALLOC_FREE ( dname ) ;
continue ;
}
2020-11-12 12:00:57 +03:00
2023-06-22 16:12:25 +03:00
mode = fdos_mode ( smb_fname - > fsp ) ;
2022-03-10 17:56:07 +03:00
2020-11-12 12:00:57 +03:00
/*
2023-06-22 16:12:25 +03:00
* Don ' t leak INO / DEV / User SID / Group SID about
* the containing directory of the share .
2020-11-12 12:00:57 +03:00
*/
2023-06-22 16:12:25 +03:00
if ( ISDOT ( dpath ) & & ISDOTDOT ( dname ) ) {
/*
* Ensure posix fileid and sids are hidden
*/
smb_fname - > st . st_ex_ino = 0 ;
smb_fname - > st . st_ex_dev = 0 ;
smb_fname - > st . st_ex_uid = - 1 ;
smb_fname - > st . st_ex_gid = - 1 ;
}
2020-11-12 12:00:57 +03:00
2023-06-22 16:12:25 +03:00
goto done ;
2021-06-04 20:10:55 +03:00
}
2023-06-22 16:12:25 +03:00
status = openat_pathref_fsp_nosymlink ( talloc_tos ( ) ,
conn ,
dir_hnd - > fsp ,
dname ,
dir_fname - > twrp ,
posix ,
& smb_fname ,
& symlink_err ) ;
2021-07-15 05:11:05 +03:00
2023-06-22 16:12:25 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
bool visible = is_visible_fsp ( smb_fname - > fsp ) ;
if ( ! visible ) {
2021-07-15 05:11:05 +03:00
TALLOC_FREE ( smb_fname ) ;
TALLOC_FREE ( dname ) ;
TALLOC_FREE ( fname ) ;
2023-06-22 16:12:25 +03:00
continue ;
}
} else if ( NT_STATUS_EQUAL ( status ,
NT_STATUS_STOPPED_ON_SYMLINK ) ) {
struct symlink_reparse_struct * reparse =
symlink_err - > reparse ;
const char * target = reparse - > substitute_name ;
bool is_msdfs_link ;
is_msdfs_link = lp_host_msdfs ( ) ;
is_msdfs_link & = lp_msdfs_root ( SNUM ( conn ) ) ;
is_msdfs_link & = ( strncmp ( target , " msdfs: " , 6 ) = = 0 ) ;
if ( is_msdfs_link ) {
char * path = NULL ;
path = full_path_from_dirfsp_at_basename (
talloc_tos ( ) ,
dir_hnd - > fsp ,
dname ) ;
if ( path = = NULL ) {
return false ;
}
smb_fname =
synthetic_smb_fname ( talloc_tos ( ) ,
path ,
NULL ,
& symlink_err - > st ,
dir_fname - > twrp ,
dir_fname - > flags ) ;
TALLOC_FREE ( path ) ;
if ( smb_fname = = NULL ) {
return false ;
}
DBG_INFO ( " Masquerading msdfs link %s as a "
" directory \n " ,
smb_fname - > base_name ) ;
smb_fname - > st . st_ex_mode =
( smb_fname - > st . st_ex_mode & ~ S_IFMT ) |
S_IFDIR ;
mode = dos_mode_msdfs ( conn ,
dname ,
& smb_fname - > st ) ;
get_dosmode = false ;
ask_sharemode = false ;
goto done ;
}
smb_fname = synthetic_smb_fname ( talloc_tos ( ) ,
dname ,
NULL ,
& symlink_err - > st ,
dir_fname - > twrp ,
dir_fname - > flags ) ;
if ( smb_fname = = NULL ) {
2021-07-15 05:11:05 +03:00
return false ;
}
2023-06-22 16:12:25 +03:00
status = openat_pathref_fsp ( dir_hnd - > fsp , smb_fname ) ;
if ( posix ) {
/*
* Posix always wants to see symlinks ,
* dangling or not . We ' ve done the
* openat_pathref_fsp ( ) to fill in
* smb_fname - > fsp just in case it ' s
* not dangling .
*/
mode = FILE_ATTRIBUTE_NORMAL ;
get_dosmode = false ;
ask_sharemode = false ;
goto done ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
/*
* Dangling symlink . Hide .
*/
TALLOC_FREE ( smb_fname ) ;
TALLOC_FREE ( fname ) ;
TALLOC_FREE ( dname ) ;
continue ;
}
} else {
DBG_NOTICE ( " Could not open %s: %s \n " ,
dname ,
nt_errstr ( status ) ) ;
TALLOC_FREE ( dname ) ;
TALLOC_FREE ( fname ) ;
2021-07-15 05:11:05 +03:00
TALLOC_FREE ( smb_fname ) ;
2023-06-22 16:12:25 +03:00
continue ;
2021-07-15 05:11:05 +03:00
}
2021-07-13 02:40:08 +03:00
ok = mode_fn ( ctx ,
private_data ,
2023-06-09 10:59:36 +03:00
dir_hnd - > fsp ,
2021-07-13 02:40:08 +03:00
smb_fname ,
get_dosmode ,
& mode ) ;
2009-08-06 22:53:13 +04:00
if ( ! ok ) {
2020-11-12 12:00:57 +03:00
TALLOC_FREE ( smb_fname ) ;
TALLOC_FREE ( dname ) ;
TALLOC_FREE ( fname ) ;
continue ;
}
2023-06-22 16:12:25 +03:00
done :
2009-08-06 22:53:13 +04:00
2013-11-13 03:17:26 +04:00
if ( ! dir_check_ftype ( mode , dirtype ) ) {
2023-06-22 12:19:29 +03:00
DBG_INFO ( " [%s] attribs 0x% " PRIx32 " didn't match "
" 0x% " PRIx32 " \n " ,
fname ,
mode ,
dirtype ) ;
2020-11-12 12:00:57 +03:00
TALLOC_FREE ( smb_fname ) ;
2009-08-06 22:53:13 +04:00
TALLOC_FREE ( dname ) ;
TALLOC_FREE ( fname ) ;
continue ;
}
2020-11-12 12:00:57 +03:00
if ( ask_sharemode & & ! S_ISDIR ( smb_fname - > st . st_ex_mode ) ) {
2009-08-06 22:53:13 +04:00
struct timespec write_time_ts ;
struct file_id fileid ;
fileid = vfs_file_id_from_sbuf ( conn ,
2020-11-12 12:00:57 +03:00
& smb_fname - > st ) ;
2011-01-26 00:57:38 +03:00
get_file_infos ( fileid , 0 , NULL , & write_time_ts ) ;
2019-12-02 18:30:50 +03:00
if ( ! is_omit_timespec ( & write_time_ts ) ) {
2020-11-12 12:00:57 +03:00
update_stat_ex_mtime ( & smb_fname - > st ,
2009-08-06 22:53:13 +04:00
write_time_ts ) ;
}
}
2023-06-22 12:19:29 +03:00
DBG_NOTICE ( " mask=[%s] found %s fname=%s (%s) \n " ,
mask ,
smb_fname_str_dbg ( smb_fname ) ,
dname ,
fname ) ;
2009-08-06 22:53:13 +04:00
TALLOC_FREE ( dname ) ;
2020-11-12 12:00:57 +03:00
* _smb_fname = talloc_move ( ctx , & smb_fname ) ;
2013-04-11 18:22:38 +04:00
if ( * _smb_fname = = NULL ) {
2009-11-15 12:46:23 +03:00
return false ;
}
2009-08-06 22:53:13 +04:00
* _fname = fname ;
* _mode = mode ;
return true ;
}
return false ;
}
2023-05-27 14:20:56 +03:00
void smbd_dirptr_push_overflow ( struct dptr_struct * dirptr ,
char * * _fname ,
struct smb_filename * * _smb_fname ,
uint32_t mode )
{
SMB_ASSERT ( dirptr - > overflow . fname = = NULL ) ;
SMB_ASSERT ( dirptr - > overflow . smb_fname = = NULL ) ;
dirptr - > overflow . fname = talloc_move ( dirptr , _fname ) ;
dirptr - > overflow . smb_fname = talloc_move ( dirptr , _smb_fname ) ;
dirptr - > overflow . mode = mode ;
}
2023-06-09 16:22:31 +03:00
void smbd_dirptr_set_last_name_sent ( struct dptr_struct * dirptr ,
char * * _fname )
{
TALLOC_FREE ( dirptr - > last_name_sent ) ;
dirptr - > last_name_sent = talloc_move ( dirptr , _fname ) ;
}
char * smbd_dirptr_get_last_name_sent ( struct dptr_struct * dirptr )
{
return dirptr - > last_name_sent ;
}
2021-06-02 21:31:45 +03:00
/*******************************************************************
Check to see if a user can read an fsp . This is only approximate ,
it is used as part of the " hide unreadable " option . Don ' t
use it for anything security sensitive .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static bool user_can_read_fsp ( struct files_struct * fsp )
{
NTSTATUS status ;
uint32_t rejected_share_access = 0 ;
uint32_t rejected_mask = 0 ;
struct security_descriptor * sd = NULL ;
uint32_t access_mask = FILE_READ_DATA |
FILE_READ_EA |
FILE_READ_ATTRIBUTES |
SEC_STD_READ_CONTROL ;
/*
* Never hide files from the root user .
* We use ( uid_t ) 0 here not sec_initial_uid ( )
* as make test uses a single user context .
*/
if ( get_current_uid ( fsp - > conn ) = = ( uid_t ) 0 ) {
return true ;
}
/*
* We can ' t directly use smbd_check_access_rights_fsp ( )
* here , as this implicitly grants FILE_READ_ATTRIBUTES
* which the Windows access - based - enumeration code
* explicitly checks for on the file security descriptor .
* See bug :
*
* https : //bugzilla.samba.org/show_bug.cgi?id=10252
*
* and the smb2 . acl2 . ACCESSBASED test for details .
*/
rejected_share_access = access_mask & ~ ( fsp - > conn - > share_access ) ;
if ( rejected_share_access ) {
DBG_DEBUG ( " rejected share access 0x%x "
" on %s (0x%x) \n " ,
( unsigned int ) access_mask ,
fsp_str_dbg ( fsp ) ,
( unsigned int ) rejected_share_access ) ;
return false ;
}
2022-07-29 15:49:56 +03:00
status = SMB_VFS_FGET_NT_ACL ( metadata_fsp ( fsp ) ,
2021-06-02 21:31:45 +03:00
( SECINFO_OWNER |
SECINFO_GROUP |
SECINFO_DACL ) ,
talloc_tos ( ) ,
& sd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " Could not get acl "
" on %s: %s \n " ,
fsp_str_dbg ( fsp ) ,
nt_errstr ( status ) ) ;
return false ;
}
status = se_file_access_check ( sd ,
get_current_nttok ( fsp - > conn ) ,
false ,
access_mask ,
& rejected_mask ) ;
TALLOC_FREE ( sd ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_ACCESS_DENIED ) ) {
DBG_DEBUG ( " rejected bits 0x%x read access for %s \n " ,
( unsigned int ) rejected_mask ,
fsp_str_dbg ( fsp ) ) ;
return false ;
}
return true ;
}
2021-06-03 03:36:16 +03:00
/*******************************************************************
Check to see if a user can write to an fsp .
Always return true for directories .
This is only approximate ,
it is used as part of the " hide unwriteable " option . Don ' t
use it for anything security sensitive .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static bool user_can_write_fsp ( struct files_struct * fsp )
{
/*
* Never hide files from the root user .
* We use ( uid_t ) 0 here not sec_initial_uid ( )
* as make test uses a single user context .
*/
if ( get_current_uid ( fsp - > conn ) = = ( uid_t ) 0 ) {
return true ;
}
if ( fsp - > fsp_flags . is_directory ) {
return true ;
}
return can_write_to_fsp ( fsp ) ;
}
2002-09-25 19:19:00 +04:00
/*******************************************************************
Is a file a " special " type ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-06-26 05:19:09 +04:00
static bool file_is_special ( connection_struct * conn ,
const struct smb_filename * smb_fname )
2002-09-25 19:19:00 +04:00
{
/*
2010-03-15 22:24:06 +03:00
* Never hide files from the root user .
* We use ( uid_t ) 0 here not sec_initial_uid ( )
* as make test uses a single user context .
2002-09-25 19:19:00 +04:00
*/
2010-03-15 22:24:06 +03:00
if ( get_current_uid ( conn ) = = ( uid_t ) 0 ) {
2003-12-23 10:33:42 +03:00
return False ;
2010-03-15 22:24:06 +03:00
}
2002-09-25 19:19:00 +04:00
2009-06-26 05:19:09 +04:00
SMB_ASSERT ( VALID_STAT ( smb_fname - > st ) ) ;
2002-09-25 19:19:00 +04:00
2009-06-26 05:19:09 +04:00
if ( S_ISREG ( smb_fname - > st . st_ex_mode ) | |
S_ISDIR ( smb_fname - > st . st_ex_mode ) | |
S_ISLNK ( smb_fname - > st . st_ex_mode ) )
2002-09-25 19:19:00 +04:00
return False ;
return True ;
}
2021-06-03 03:30:26 +03:00
/*******************************************************************
Should the file be seen by the client ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2021-06-04 23:32:40 +03:00
bool is_visible_fsp ( struct files_struct * fsp )
2021-06-03 03:30:26 +03:00
{
bool hide_unreadable = false ;
bool hide_unwriteable = false ;
bool hide_special = false ;
int hide_new_files_timeout = 0 ;
const char * last_component = NULL ;
/*
* If the file does not exist , there ' s no point checking
* the configuration options . We succeed , on the basis that the
* checks * might * have passed if the file was present .
*/
if ( fsp = = NULL ) {
return true ;
}
hide_unreadable = lp_hide_unreadable ( SNUM ( fsp - > conn ) ) ;
hide_unwriteable = lp_hide_unwriteable_files ( SNUM ( fsp - > conn ) ) ;
hide_special = lp_hide_special_files ( SNUM ( fsp - > conn ) ) ;
hide_new_files_timeout = lp_hide_new_files_timeout ( SNUM ( fsp - > conn ) ) ;
2021-11-03 16:40:01 +03:00
if ( ! hide_unreadable & &
! hide_unwriteable & &
! hide_special & &
( hide_new_files_timeout = = 0 ) )
{
return true ;
}
2022-02-11 11:45:30 +03:00
fsp = metadata_fsp ( fsp ) ;
2021-06-03 03:30:26 +03:00
/* Get the last component of the base name. */
last_component = strrchr_m ( fsp - > fsp_name - > base_name , ' / ' ) ;
if ( ! last_component ) {
last_component = fsp - > fsp_name - > base_name ;
} else {
last_component + + ; /* Go past '/' */
}
if ( ISDOT ( last_component ) | | ISDOTDOT ( last_component ) ) {
return true ; /* . and .. are always visible. */
}
2021-06-04 20:09:34 +03:00
if ( fsp_get_pathref_fd ( fsp ) = = - 1 ) {
/*
* Symlink in POSIX mode or MS - DFS .
* We ' ve checked veto files so the
* only thing we can check is the
* hide_new_files_timeout .
*/
2022-11-07 17:08:51 +03:00
if ( ( hide_new_files_timeout ! = 0 ) & &
! S_ISDIR ( fsp - > fsp_name - > st . st_ex_mode ) ) {
2021-06-04 20:09:34 +03:00
double age = timespec_elapsed (
& fsp - > fsp_name - > st . st_ex_mtime ) ;
if ( age < ( double ) hide_new_files_timeout ) {
return false ;
}
}
return true ;
}
2022-12-07 12:49:47 +03:00
/* Honour _hide unreadable_ option */
if ( hide_unreadable & & ! user_can_read_fsp ( fsp ) ) {
DBG_DEBUG ( " file %s is unreadable. \n " , fsp_str_dbg ( fsp ) ) ;
return false ;
}
2021-06-03 03:30:26 +03:00
2022-12-07 12:49:47 +03:00
/* Honour _hide unwriteable_ option */
if ( hide_unwriteable & & ! user_can_write_fsp ( fsp ) ) {
DBG_DEBUG ( " file %s is unwritable. \n " , fsp_str_dbg ( fsp ) ) ;
return false ;
}
2021-06-03 03:30:26 +03:00
2022-12-07 12:49:47 +03:00
/* Honour _hide_special_ option */
if ( hide_special & & file_is_special ( fsp - > conn , fsp - > fsp_name ) ) {
DBG_DEBUG ( " file %s is special. \n " , fsp_str_dbg ( fsp ) ) ;
return false ;
}
if ( ( hide_new_files_timeout ! = 0 ) & &
! S_ISDIR ( fsp - > fsp_name - > st . st_ex_mode ) ) {
double age = timespec_elapsed ( & fsp - > fsp_name - > st . st_ex_mtime ) ;
if ( age < ( double ) hide_new_files_timeout ) {
return false ;
2021-06-03 03:30:26 +03:00
}
}
return true ;
}
2019-07-17 19:40:04 +03:00
static int smb_Dir_destructor ( struct smb_Dir * dir_hnd )
2008-01-12 19:08:04 +03:00
{
2019-07-18 01:25:11 +03:00
files_struct * fsp = dir_hnd - > fsp ;
SMB_VFS_CLOSEDIR ( dir_hnd - > conn , dir_hnd - > dir ) ;
2020-09-26 22:46:51 +03:00
fsp_set_fd ( fsp , - 1 ) ;
2020-03-18 20:25:33 +03:00
if ( fsp - > dptr ! = NULL ) {
SMB_ASSERT ( fsp - > dptr - > dir_hnd = = dir_hnd ) ;
fsp - > dptr - > dir_hnd = NULL ;
}
2019-07-18 01:25:11 +03:00
dir_hnd - > fsp = NULL ;
2008-01-12 19:08:04 +03:00
return 0 ;
}
1996-05-04 11:50:46 +04:00
/*******************************************************************
1999-12-13 16:27:58 +03:00
Open a directory .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2020-03-18 18:01:17 +03:00
static int smb_Dir_OpenDir_destructor ( struct smb_Dir * dir_hnd )
1996-05-04 11:50:46 +04:00
{
2020-03-18 18:01:17 +03:00
files_struct * fsp = dir_hnd - > fsp ;
2011-02-10 03:31:06 +03:00
2020-03-18 18:01:17 +03:00
smb_Dir_destructor ( dir_hnd ) ;
file_free ( NULL , fsp ) ;
return 0 ;
2011-02-10 03:31:06 +03:00
}
2022-03-01 01:34:48 +03:00
NTSTATUS OpenDir ( TALLOC_CTX * mem_ctx ,
connection_struct * conn ,
const struct smb_filename * smb_dname ,
const char * mask ,
uint32_t attr ,
struct smb_Dir * * _dir_hnd )
2016-12-20 03:35:00 +03:00
{
2020-03-18 18:01:17 +03:00
struct files_struct * fsp = NULL ;
2016-12-20 03:35:00 +03:00
struct smb_Dir * dir_hnd = NULL ;
NTSTATUS status ;
2020-05-15 16:14:26 +03:00
status = open_internal_dirfsp ( conn ,
smb_dname ,
O_RDONLY ,
& fsp ) ;
2016-12-20 03:35:00 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2022-02-21 19:17:24 +03:00
return status ;
2016-12-20 03:35:00 +03:00
}
2022-02-21 19:12:05 +03:00
status = OpenDir_fsp ( mem_ctx , conn , fsp , mask , attr , & dir_hnd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2022-02-21 19:17:24 +03:00
return status ;
2016-12-20 03:35:00 +03:00
}
/*
2022-03-13 17:22:50 +03:00
* This overwrites the destructor set by OpenDir_fsp ( ) but
* smb_Dir_OpenDir_destructor ( ) calls the OpenDir_fsp ( )
* destructor .
2016-12-20 03:35:00 +03:00
*/
2019-07-17 19:31:46 +03:00
talloc_set_destructor ( dir_hnd , smb_Dir_OpenDir_destructor ) ;
2022-02-21 19:17:24 +03:00
* _dir_hnd = dir_hnd ;
return NT_STATUS_OK ;
2016-12-19 22:55:56 +03:00
}
2022-03-13 17:42:31 +03:00
NTSTATUS OpenDir_from_pathref ( TALLOC_CTX * mem_ctx ,
struct files_struct * dirfsp ,
const char * mask ,
uint32_t attr ,
struct smb_Dir * * _dir_hnd )
{
struct files_struct * fsp = NULL ;
struct smb_Dir * dir_hnd = NULL ;
NTSTATUS status ;
status = openat_internal_dir_from_pathref ( dirfsp , O_RDONLY , & fsp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = OpenDir_fsp ( mem_ctx , fsp - > conn , fsp , mask , attr , & dir_hnd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
/*
* This overwrites the destructor set by OpenDir_fsp ( ) but
* smb_Dir_OpenDir_destructor ( ) calls the OpenDir_fsp ( )
* destructor .
*/
talloc_set_destructor ( dir_hnd , smb_Dir_OpenDir_destructor ) ;
* _dir_hnd = dir_hnd ;
return NT_STATUS_OK ;
}
2011-02-10 03:31:06 +03:00
/*******************************************************************
Open a directory from an fsp .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2022-02-21 19:12:05 +03:00
static NTSTATUS OpenDir_fsp (
TALLOC_CTX * mem_ctx ,
connection_struct * conn ,
files_struct * fsp ,
const char * mask ,
uint32_t attr ,
struct smb_Dir * * _dir_hnd )
2011-02-10 03:31:06 +03:00
{
2019-07-17 19:47:31 +03:00
struct smb_Dir * dir_hnd = talloc_zero ( mem_ctx , struct smb_Dir ) ;
2022-02-21 19:12:05 +03:00
NTSTATUS status ;
2011-02-10 03:31:06 +03:00
2019-07-17 19:47:31 +03:00
if ( ! dir_hnd ) {
2022-02-21 19:12:05 +03:00
return NT_STATUS_NO_MEMORY ;
2016-12-19 23:13:20 +03:00
}
2020-04-02 19:21:11 +03:00
if ( ! fsp - > fsp_flags . is_directory ) {
2022-02-21 19:12:05 +03:00
status = NT_STATUS_INVALID_HANDLE ;
2016-12-19 23:13:20 +03:00
goto fail ;
}
2020-09-26 22:46:51 +03:00
if ( fsp_get_io_fd ( fsp ) = = - 1 ) {
2022-02-21 19:12:05 +03:00
status = NT_STATUS_INVALID_HANDLE ;
2016-12-19 23:13:20 +03:00
goto fail ;
2011-02-10 03:31:06 +03:00
}
2019-07-17 19:47:31 +03:00
dir_hnd - > conn = conn ;
2018-03-29 21:06:47 +03:00
2019-07-17 19:47:31 +03:00
dir_hnd - > dir_smb_fname = cp_smb_filename ( dir_hnd , fsp - > fsp_name ) ;
if ( ! dir_hnd - > dir_smb_fname ) {
2022-02-21 19:12:05 +03:00
status = NT_STATUS_NO_MEMORY ;
2005-01-29 00:01:58 +03:00
goto fail ;
}
2008-01-12 19:08:04 +03:00
2019-07-17 19:47:31 +03:00
dir_hnd - > dir = SMB_VFS_FDOPENDIR ( fsp , mask , attr ) ;
if ( dir_hnd - > dir = = NULL ) {
2022-02-21 19:12:05 +03:00
status = map_nt_error_from_unix ( errno ) ;
2020-03-18 17:59:11 +03:00
goto fail ;
2011-02-10 02:05:58 +03:00
}
2020-03-18 17:59:11 +03:00
dir_hnd - > fsp = fsp ;
2021-11-06 02:43:14 +03:00
if ( fsp - > posix_flags & FSP_POSIX_FLAGS_OPEN ) {
dir_hnd - > case_sensitive = true ;
} else {
dir_hnd - > case_sensitive = conn - > case_sensitive ;
}
2011-02-10 02:05:58 +03:00
2019-07-17 19:47:31 +03:00
talloc_set_destructor ( dir_hnd , smb_Dir_destructor ) ;
2016-12-19 23:32:07 +03:00
2022-02-21 19:12:05 +03:00
* _dir_hnd = dir_hnd ;
return NT_STATUS_OK ;
2002-08-17 19:27:10 +04:00
2005-01-29 00:01:58 +03:00
fail :
2019-07-17 19:47:31 +03:00
TALLOC_FREE ( dir_hnd ) ;
2022-02-21 19:12:05 +03:00
return status ;
1996-05-04 11:50:46 +04:00
}
2011-02-10 03:31:06 +03:00
1996-05-04 11:50:46 +04:00
/*******************************************************************
2009-01-23 07:18:56 +03:00
Read from a directory .
Return directory entry , current offset , and optional stat information .
2005-02-01 21:33:50 +03:00
Don ' t check for veto or invisible files .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2023-06-20 13:25:45 +03:00
const char * ReadDirName ( struct smb_Dir * dir_hnd , char * * ptalloced )
1996-05-04 11:50:46 +04:00
{
2009-11-16 11:49:23 +03:00
const char * n ;
char * talloced = NULL ;
2019-07-17 19:51:07 +03:00
connection_struct * conn = dir_hnd - > conn ;
1996-05-04 11:50:46 +04:00
2023-06-10 16:29:35 +03:00
if ( dir_hnd - > file_number < 2 ) {
2019-07-17 19:51:07 +03:00
if ( dir_hnd - > file_number = = 0 ) {
2009-11-16 11:49:23 +03:00
n = " . " ;
2005-06-11 03:13:25 +04:00
} else {
2009-11-16 11:49:23 +03:00
n = " .. " ;
2005-06-11 03:13:25 +04:00
}
2019-07-17 19:51:07 +03:00
dir_hnd - > file_number + + ;
2009-11-16 11:49:23 +03:00
* ptalloced = NULL ;
2005-06-11 03:13:25 +04:00
return n ;
2015-02-24 16:46:09 +03:00
}
2023-06-20 13:25:45 +03:00
while ( ( n = vfs_readdirname ( conn ,
dir_hnd - > fsp ,
dir_hnd - > dir ,
& talloced ) ) ) {
2005-06-11 03:13:25 +04:00
/* Ignore . and .. - we've already returned them. */
2022-03-12 14:47:54 +03:00
if ( ISDOT ( n ) | | ISDOTDOT ( n ) ) {
TALLOC_FREE ( talloced ) ;
continue ;
2005-06-11 03:13:25 +04:00
}
2009-11-16 11:49:23 +03:00
* ptalloced = talloced ;
2019-07-17 19:51:07 +03:00
dir_hnd - > file_number + + ;
2006-04-08 09:00:04 +04:00
return n ;
2003-01-03 21:50:13 +03:00
}
2009-11-16 11:49:23 +03:00
* ptalloced = NULL ;
2005-01-29 00:01:58 +03:00
return NULL ;
}
2005-06-15 22:37:34 +04:00
/*******************************************************************
Rewind to the start .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2023-06-10 16:29:35 +03:00
void RewindDir ( struct smb_Dir * dir_hnd )
2005-06-15 22:37:34 +04:00
{
2019-07-17 19:52:41 +03:00
SMB_VFS_REWINDDIR ( dir_hnd - > conn , dir_hnd - > dir ) ;
dir_hnd - > file_number = 0 ;
2005-01-29 00:01:58 +03:00
}
1996-05-04 11:50:46 +04:00
2014-09-25 03:30:33 +04:00
struct files_below_forall_state {
char * dirpath ;
2020-12-01 15:27:11 +03:00
ssize_t dirpath_len ;
2014-09-25 03:30:33 +04:00
int ( * fn ) ( struct file_id fid , const struct share_mode_data * data ,
void * private_data ) ;
void * private_data ;
} ;
static int files_below_forall_fn ( struct file_id fid ,
const struct share_mode_data * data ,
void * private_data )
{
struct files_below_forall_state * state = private_data ;
char tmpbuf [ PATH_MAX ] ;
char * fullpath , * to_free ;
2020-12-01 15:27:11 +03:00
ssize_t len ;
2014-09-25 03:30:33 +04:00
len = full_path_tos ( data - > servicepath , data - > base_name ,
tmpbuf , sizeof ( tmpbuf ) ,
& fullpath , & to_free ) ;
if ( len = = - 1 ) {
return 0 ;
}
if ( state - > dirpath_len > = len ) {
/*
* Filter files above dirpath
*/
2018-03-06 12:35:32 +03:00
goto out ;
2014-09-25 03:30:33 +04:00
}
if ( fullpath [ state - > dirpath_len ] ! = ' / ' ) {
/*
* Filter file that don ' t have a path separator at the end of
* dirpath ' s length
*/
2018-03-06 12:35:32 +03:00
goto out ;
2014-09-25 03:30:33 +04:00
}
2015-11-24 01:00:56 +03:00
if ( memcmp ( state - > dirpath , fullpath , state - > dirpath_len ) ! = 0 ) {
2014-09-25 03:30:33 +04:00
/*
* Not a parent
*/
2018-03-06 12:35:32 +03:00
goto out ;
2014-09-25 03:30:33 +04:00
}
2018-03-06 12:35:32 +03:00
TALLOC_FREE ( to_free ) ;
2015-11-24 01:00:56 +03:00
return state - > fn ( fid , data , state - > private_data ) ;
2018-03-06 12:35:32 +03:00
out :
TALLOC_FREE ( to_free ) ;
return 0 ;
2014-09-25 03:30:33 +04:00
}
static int files_below_forall ( connection_struct * conn ,
const struct smb_filename * dir_name ,
int ( * fn ) ( struct file_id fid ,
const struct share_mode_data * data ,
void * private_data ) ,
void * private_data )
{
2015-11-24 01:00:56 +03:00
struct files_below_forall_state state = {
. fn = fn ,
. private_data = private_data ,
} ;
2014-09-25 03:30:33 +04:00
int ret ;
char tmpbuf [ PATH_MAX ] ;
char * to_free ;
state . dirpath_len = full_path_tos ( conn - > connectpath ,
dir_name - > base_name ,
tmpbuf , sizeof ( tmpbuf ) ,
& state . dirpath , & to_free ) ;
if ( state . dirpath_len = = - 1 ) {
return - 1 ;
}
ret = share_mode_forall ( files_below_forall_fn , & state ) ;
TALLOC_FREE ( to_free ) ;
return ret ;
}
struct have_file_open_below_state {
bool found_one ;
} ;
static int have_file_open_below_fn ( struct file_id fid ,
const struct share_mode_data * data ,
void * private_data )
{
struct have_file_open_below_state * state = private_data ;
state - > found_one = true ;
return 1 ;
}
2015-11-24 19:43:14 +03:00
bool have_file_open_below ( connection_struct * conn ,
2014-09-25 03:30:33 +04:00
const struct smb_filename * name )
{
2015-11-24 01:00:56 +03:00
struct have_file_open_below_state state = {
. found_one = false ,
} ;
2014-09-25 03:30:33 +04:00
int ret ;
if ( ! VALID_STAT ( name - > st ) ) {
return false ;
}
if ( ! S_ISDIR ( name - > st . st_ex_mode ) ) {
return false ;
}
ret = files_below_forall ( conn , name , have_file_open_below_fn , & state ) ;
if ( ret = = - 1 ) {
return false ;
}
return state . found_one ;
}
2007-02-09 05:03:39 +03:00
/*****************************************************************
Is this directory empty ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-11-15 02:40:51 +04:00
NTSTATUS can_delete_directory_fsp ( files_struct * fsp )
2007-02-09 05:03:39 +03:00
{
NTSTATUS status = NT_STATUS_OK ;
2009-11-16 11:49:23 +03:00
const char * dname = NULL ;
char * talloced = NULL ;
2012-11-15 02:40:51 +04:00
struct connection_struct * conn = fsp - > conn ;
2022-02-21 19:19:49 +03:00
struct smb_Dir * dir_hnd = NULL ;
2007-02-09 05:03:39 +03:00
2022-03-01 01:34:48 +03:00
status = OpenDir (
2022-02-21 19:19:49 +03:00
talloc_tos ( ) , conn , fsp - > fsp_name , NULL , 0 , & dir_hnd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
2007-02-09 05:03:39 +03:00
}
2023-06-20 13:25:45 +03:00
while ( ( dname = ReadDirName ( dir_hnd , & talloced ) ) ) {
2021-06-04 23:21:29 +03:00
struct smb_filename * smb_dname_full = NULL ;
struct smb_filename * direntry_fname = NULL ;
char * fullname = NULL ;
int ret ;
2020-10-28 17:40:39 +03:00
if ( ISDOT ( dname ) | | ( ISDOTDOT ( dname ) ) ) {
TALLOC_FREE ( talloced ) ;
continue ;
2007-02-09 05:03:39 +03:00
}
2021-06-04 22:47:11 +03:00
if ( IS_VETO_PATH ( conn , dname ) ) {
TALLOC_FREE ( talloced ) ;
continue ;
}
2021-06-04 23:21:29 +03:00
fullname = talloc_asprintf ( talloc_tos ( ) ,
" %s/%s " ,
fsp - > fsp_name - > base_name ,
dname ) ;
if ( fullname = = NULL ) {
status = NT_STATUS_NO_MEMORY ;
break ;
}
smb_dname_full = synthetic_smb_fname ( talloc_tos ( ) ,
fullname ,
NULL ,
NULL ,
fsp - > fsp_name - > twrp ,
fsp - > fsp_name - > flags ) ;
if ( smb_dname_full = = NULL ) {
TALLOC_FREE ( talloced ) ;
TALLOC_FREE ( fullname ) ;
status = NT_STATUS_NO_MEMORY ;
break ;
}
ret = SMB_VFS_LSTAT ( conn , smb_dname_full ) ;
if ( ret ! = 0 ) {
status = map_nt_error_from_unix ( errno ) ;
TALLOC_FREE ( talloced ) ;
TALLOC_FREE ( fullname ) ;
TALLOC_FREE ( smb_dname_full ) ;
break ;
}
if ( S_ISLNK ( smb_dname_full - > st . st_ex_mode ) ) {
2021-10-25 22:36:57 +03:00
/* Could it be an msdfs link ? */
if ( lp_host_msdfs ( ) & &
lp_msdfs_root ( SNUM ( conn ) ) ) {
struct smb_filename * smb_dname ;
smb_dname = synthetic_smb_fname ( talloc_tos ( ) ,
dname ,
NULL ,
& smb_dname_full - > st ,
fsp - > fsp_name - > twrp ,
fsp - > fsp_name - > flags ) ;
if ( smb_dname = = NULL ) {
TALLOC_FREE ( talloced ) ;
TALLOC_FREE ( fullname ) ;
TALLOC_FREE ( smb_dname_full ) ;
status = NT_STATUS_NO_MEMORY ;
break ;
}
if ( is_msdfs_link ( fsp , smb_dname ) ) {
TALLOC_FREE ( talloced ) ;
TALLOC_FREE ( fullname ) ;
TALLOC_FREE ( smb_dname_full ) ;
TALLOC_FREE ( smb_dname ) ;
DBG_DEBUG ( " got msdfs link name %s "
" - can't delete directory %s \n " ,
dname ,
fsp_str_dbg ( fsp ) ) ;
status = NT_STATUS_DIRECTORY_NOT_EMPTY ;
break ;
}
TALLOC_FREE ( smb_dname ) ;
}
/* Not a DFS link - could it be a dangling symlink ? */
ret = SMB_VFS_STAT ( conn , smb_dname_full ) ;
if ( ret = = - 1 & & ( errno = = ENOENT | | errno = = ELOOP ) ) {
/*
* Dangling symlink .
* Allow if " delete veto files = yes "
*/
if ( lp_delete_veto_files ( SNUM ( conn ) ) ) {
TALLOC_FREE ( talloced ) ;
TALLOC_FREE ( fullname ) ;
TALLOC_FREE ( smb_dname_full ) ;
continue ;
}
}
DBG_DEBUG ( " got symlink name %s - "
" can't delete directory %s \n " ,
dname ,
fsp_str_dbg ( fsp ) ) ;
2021-06-04 23:21:29 +03:00
TALLOC_FREE ( talloced ) ;
TALLOC_FREE ( fullname ) ;
TALLOC_FREE ( smb_dname_full ) ;
status = NT_STATUS_DIRECTORY_NOT_EMPTY ;
break ;
}
/* Not a symlink, get a pathref. */
status = synthetic_pathref ( talloc_tos ( ) ,
fsp ,
dname ,
NULL ,
& smb_dname_full - > st ,
fsp - > fsp_name - > twrp ,
fsp - > fsp_name - > flags ,
& direntry_fname ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
status = map_nt_error_from_unix ( errno ) ;
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2021-06-04 23:21:29 +03:00
TALLOC_FREE ( fullname ) ;
TALLOC_FREE ( smb_dname_full ) ;
break ;
}
2021-06-04 23:32:40 +03:00
if ( ! is_visible_fsp ( direntry_fname - > fsp ) ) {
2022-03-21 23:50:56 +03:00
/*
* Hidden file .
* Allow if " delete veto files = yes "
*/
if ( lp_delete_veto_files ( SNUM ( conn ) ) ) {
TALLOC_FREE ( talloced ) ;
TALLOC_FREE ( fullname ) ;
TALLOC_FREE ( smb_dname_full ) ;
TALLOC_FREE ( direntry_fname ) ;
continue ;
}
2007-02-09 05:03:39 +03:00
}
2021-06-04 23:21:29 +03:00
TALLOC_FREE ( talloced ) ;
TALLOC_FREE ( fullname ) ;
TALLOC_FREE ( smb_dname_full ) ;
TALLOC_FREE ( direntry_fname ) ;
DBG_DEBUG ( " got name %s - can't delete \n " , dname ) ;
2007-02-09 05:03:39 +03:00
status = NT_STATUS_DIRECTORY_NOT_EMPTY ;
break ;
}
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2008-01-12 19:08:04 +03:00
TALLOC_FREE ( dir_hnd ) ;
2007-02-09 05:03:39 +03:00
2014-09-25 03:30:33 +04:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2016-01-16 03:22:26 +03:00
if ( ! ( fsp - > posix_flags & FSP_POSIX_FLAGS_RENAME ) & &
2014-09-25 03:30:33 +04:00
lp_strict_rename ( SNUM ( conn ) ) & &
have_file_open_below ( fsp - > conn , fsp - > fsp_name ) )
{
return NT_STATUS_ACCESS_DENIED ;
}
return NT_STATUS_OK ;
2007-02-09 05:03:39 +03:00
}