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"
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"
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)
2014-01-12 02:56:57 +04:00
/* "Special" directory offsets in 32-bit wire format. */
# define WIRE_END_OF_DIRECTORY_OFFSET ((uint32_t)0xFFFFFFFF)
# define WIRE_START_OF_DIRECTORY_OFFSET ((uint32_t)0)
# define WIRE_DOT_DOT_DIRECTORY_OFFSET ((uint32_t)0x80000000)
2005-02-01 03:28:20 +03:00
/* Make directory handle internals available. */
struct name_cache_entry {
char * name ;
long offset ;
} ;
struct smb_Dir {
connection_struct * conn ;
2012-03-28 06:22:03 +04:00
DIR * dir ;
2005-02-01 03:28:20 +03:00
long offset ;
2016-02-27 01:59:51 +03:00
struct smb_filename * dir_smb_fname ;
2007-08-24 01:53:00 +04:00
size_t name_cache_size ;
2005-02-01 03:28:20 +03:00
struct name_cache_entry * name_cache ;
unsigned int name_cache_index ;
2005-06-11 03:13:25 +04:00
unsigned int file_number ;
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 ;
2015-05-03 07:01:14 +03:00
uint16_t spid ;
2005-02-01 03:28:20 +03:00
struct connection_struct * conn ;
struct smb_Dir * dir_hnd ;
2007-10-19 04:40:25 +04:00
bool expect_close ;
2005-02-01 03:28:20 +03:00
char * wcard ;
2015-05-03 07:01:14 +03:00
uint32_t attr ;
2016-02-27 03:35:17 +03:00
struct smb_filename * smb_dname ;
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 ;
struct memcache * dptr_cache ;
2005-02-01 03:28:20 +03:00
} ;
1996-05-04 11:50:46 +04:00
2011-02-10 03:31:06 +03:00
static struct smb_Dir * OpenDir_fsp ( TALLOC_CTX * mem_ctx , connection_struct * conn ,
files_struct * fsp ,
const char * mask ,
2015-05-03 07:01:14 +03:00
uint32_t attr ) ;
1996-05-04 11:50:46 +04:00
2013-04-16 03:54:20 +04:00
static void DirCacheAdd ( struct smb_Dir * dirp , const char * name , long offset ) ;
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
}
/****************************************************************************
1999-12-13 16:27:58 +03:00
Idle a dptr - the directory is closed but the control info is kept .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2005-02-01 03:28:20 +03:00
static void dptr_idle ( struct dptr_struct * dptr )
1996-05-04 11:50:46 +04:00
{
2005-02-01 03:28:20 +03:00
if ( dptr - > dir_hnd ) {
2003-01-03 21:50:13 +03:00
DEBUG ( 4 , ( " Idling dptr dnum %d \n " , dptr - > dnum ) ) ;
2008-01-12 19:08:04 +03:00
TALLOC_FREE ( dptr - > dir_hnd ) ;
2014-01-12 03:45:48 +04:00
TALLOC_FREE ( dptr - > dptr_cache ) ;
dptr - > counter = 0 ;
2003-01-03 21:50:13 +03:00
}
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
1999-12-13 16:27:58 +03:00
Idle the oldest dptr .
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 void dptr_idleoldest ( struct smbd_server_connection * sconn )
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
/*
* Go to the end of the list .
*/
2011-03-18 02:16:54 +03:00
dptr = DLIST_TAIL ( sconn - > searches . dirptrs ) ;
2003-01-03 21:50:13 +03:00
if ( ! dptr ) {
DEBUG ( 0 , ( " No dptrs available to idle ? \n " ) ) ;
return ;
}
/*
* Idle the oldest pointer .
*/
2010-02-06 04:42:29 +03:00
for ( ; dptr ; dptr = DLIST_PREV ( dptr ) ) {
2005-02-01 03:28:20 +03:00
if ( dptr - > dir_hnd ) {
2003-01-03 21:50:13 +03:00
dptr_idle ( dptr ) ;
return ;
}
}
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 ,
int key , bool forclose )
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
2011-03-18 02:16:54 +03:00
for ( dptr = sconn - > searches . dirptrs ; dptr ; dptr = dptr - > next ) {
2003-01-03 21:50:13 +03:00
if ( dptr - > dnum = = key ) {
2005-02-01 03:28:20 +03:00
if ( ! forclose & & ! dptr - > dir_hnd ) {
2011-03-18 02:16:54 +03:00
if ( sconn - > searches . dirhandles_open > = MAX_OPEN_DIRECTORIES )
2009-08-06 14:15:51 +04:00
dptr_idleoldest ( sconn ) ;
2005-02-01 03:28:20 +03:00
DEBUG ( 4 , ( " dptr_get: Reopening dptr key %d \n " , key ) ) ;
2016-02-27 02:55:14 +03:00
if ( ! ( dptr - > dir_hnd = OpenDir ( NULL ,
dptr - > conn ,
2016-02-27 03:35:17 +03:00
dptr - > smb_dname ,
2016-02-27 02:55:14 +03:00
dptr - > wcard ,
dptr - > attr ) ) ) {
DEBUG ( 4 , ( " dptr_get: Failed to "
" open %s (%s) \n " ,
2016-02-27 03:35:17 +03:00
dptr - > smb_dname - > base_name ,
2005-02-01 03:28:20 +03:00
strerror ( errno ) ) ) ;
2011-12-20 13:25:05 +04:00
return NULL ;
2005-02-01 03:28:20 +03:00
}
2003-01-03 21:50:13 +03:00
}
2011-03-18 02:16:54 +03:00
DLIST_PROMOTE ( sconn - > searches . dirptrs , dptr ) ;
2003-01-03 21:50:13 +03:00
return dptr ;
}
}
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
{
2009-08-06 14:15:51 +04:00
struct dptr_struct * dptr = dptr_get ( sconn , key , false ) ;
2003-01-03 21:50:13 +03:00
if ( dptr )
2016-02-27 03:35:17 +03:00
return ( dptr - > smb_dname - > 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
{
2009-08-06 14:15:51 +04:00
struct dptr_struct * dptr = dptr_get ( sconn , key , false ) ;
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
{
2009-08-06 14:15:51 +04:00
struct dptr_struct * dptr = dptr_get ( sconn , key , false ) ;
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 a dptr ( internal func ) .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2005-02-01 03:28:20 +03:00
static void dptr_close_internal ( struct dptr_struct * dptr )
1996-05-04 11:50:46 +04:00
{
2009-08-06 14:15:51 +04:00
struct smbd_server_connection * sconn = dptr - > conn - > sconn ;
2003-01-03 21:50:13 +03:00
DEBUG ( 4 , ( " closing dptr key %d \n " , dptr - > dnum ) ) ;
1999-12-13 16:27:58 +03:00
2009-08-06 14:15:51 +04:00
if ( sconn = = NULL ) {
goto done ;
}
2011-11-09 19:04:09 +04:00
if ( sconn - > using_smb2 ) {
goto done ;
}
2011-03-18 02:16:54 +03:00
DLIST_REMOVE ( sconn - > searches . dirptrs , dptr ) ;
1999-12-13 16:27:58 +03:00
2007-09-13 01:48:20 +04:00
/*
2003-01-03 21:50:13 +03:00
* Free the dnum in the bitmap . Remember the dnum value is always
* biased by one with respect to the bitmap .
*/
1999-12-13 16:27:58 +03:00
2011-03-18 02:16:54 +03:00
if ( ! bitmap_query ( sconn - > searches . dptr_bmap , dptr - > dnum - 1 ) ) {
2003-01-03 21:50:13 +03:00
DEBUG ( 0 , ( " dptr_close_internal : Error - closing dnum = %d and bitmap not set ! \n " ,
1999-12-13 16:27:58 +03:00
dptr - > dnum ) ) ;
2003-01-03 21:50:13 +03:00
}
1999-12-13 16:27:58 +03:00
2011-03-18 02:16:54 +03:00
bitmap_clear ( sconn - > searches . dptr_bmap , dptr - > dnum - 1 ) ;
1999-12-13 16:27:58 +03:00
2009-08-06 14:15:51 +04:00
done :
2008-01-12 19:08:04 +03:00
TALLOC_FREE ( dptr - > dir_hnd ) ;
2012-02-25 05:16:08 +04:00
TALLOC_FREE ( dptr ) ;
1999-12-13 16:27:58 +03:00
}
/****************************************************************************
Close a dptr given a key .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-08-06 14:15:51 +04:00
void dptr_close ( struct smbd_server_connection * sconn , int * key )
1999-12-13 16:27:58 +03:00
{
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
if ( * key = = INVALID_DPTR_KEY )
return ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
/* OS/2 seems to use -1 to indicate "close all directories" */
if ( * key = = - 1 ) {
2005-02-01 03:28:20 +03:00
struct dptr_struct * next ;
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 ;
dptr_close_internal ( dptr ) ;
}
* key = INVALID_DPTR_KEY ;
return ;
}
1996-05-05 15:23:23 +04:00
2009-08-06 14:15:51 +04:00
dptr = dptr_get ( sconn , * key , true ) ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
if ( ! dptr ) {
DEBUG ( 0 , ( " Invalid key %d given to dptr_close \n " , * key ) ) ;
return ;
}
1996-05-05 15:23:23 +04:00
2003-01-03 21:50:13 +03:00
dptr_close_internal ( dptr ) ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
* key = INVALID_DPTR_KEY ;
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 ) {
2003-01-03 21:50:13 +03:00
dptr_close_internal ( dptr ) ;
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
Idle 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_idlecnum ( connection_struct * conn )
1996-05-04 11:50:46 +04:00
{
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr ;
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 = dptr - > next ) {
2009-08-06 14:15:51 +04:00
if ( dptr - > conn = = conn & & dptr - > dir_hnd ) {
2003-01-03 21:50:13 +03:00
dptr_idle ( dptr ) ;
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
Close a dptr that matches a given path , only if it matches the spid also .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2009-08-06 14:15:51 +04:00
void dptr_closepath ( struct smbd_server_connection * sconn ,
2015-05-03 07:01:14 +03:00
char * path , uint16_t spid )
1996-05-04 11:50:46 +04:00
{
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr , * next ;
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 ;
2016-02-27 03:35:17 +03:00
if ( spid = = dptr - > spid & &
strequal ( dptr - > smb_dname - > base_name , path ) ) {
2003-01-03 21:50:13 +03:00
dptr_close_internal ( dptr ) ;
2016-02-27 03:35:17 +03: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
/****************************************************************************
Try and close the oldest handle not marked for
expect close in the hope that the client has
finished with that one .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-08-06 14:15:51 +04:00
static void dptr_close_oldest ( struct smbd_server_connection * sconn ,
bool old )
1999-12-13 16:27:58 +03:00
{
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr ;
2003-01-03 21:50:13 +03:00
/*
* Go to the end of the list .
*/
2011-03-18 02:16:54 +03:00
for ( dptr = sconn - > searches . dirptrs ; dptr & & dptr - > next ; dptr = dptr - > next )
2003-01-03 21:50:13 +03:00
;
if ( ! dptr ) {
DEBUG ( 0 , ( " No old dptrs available to close oldest ? \n " ) ) ;
return ;
}
/*
* If ' old ' is true , close the oldest oldhandle dnum ( ie . 1 < dnum < 256 ) that
* does not have expect_close set . If ' old ' is false , close
* one of the new dnum handles .
*/
2010-02-06 04:42:29 +03:00
for ( ; dptr ; dptr = DLIST_PREV ( dptr ) ) {
2003-01-03 21:50:13 +03:00
if ( ( old & & ( dptr - > dnum < 256 ) & & ! dptr - > expect_close ) | |
( ! old & & ( dptr - > dnum > 255 ) ) ) {
dptr_close_internal ( dptr ) ;
return ;
}
}
1999-12-13 16:27:58 +03:00
}
1996-05-04 11:50:46 +04:00
2012-03-01 04:05:50 +04:00
/****************************************************************************
Safely do an OpenDir as root , ensuring we ' re in the right place .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct smb_Dir * open_dir_with_privilege ( connection_struct * conn ,
struct smb_request * req ,
2016-02-27 03:35:17 +03:00
const struct smb_filename * smb_dname ,
2012-03-01 04:05:50 +04:00
const char * wcard ,
uint32_t attr )
{
struct smb_Dir * dir_hnd = NULL ;
2013-04-15 13:02:19 +04:00
struct smb_filename * smb_fname_cwd ;
2012-03-01 04:05:50 +04:00
char * saved_dir = vfs_GetWd ( talloc_tos ( ) , conn ) ;
struct privilege_paths * priv_paths = req - > priv_paths ;
int ret ;
if ( saved_dir = = NULL ) {
return NULL ;
}
2016-02-27 03:35:17 +03:00
if ( vfs_ChDir ( conn , smb_dname - > base_name ) = = - 1 ) {
2012-03-01 04:05:50 +04:00
return NULL ;
}
/* Now check the stat value is the same. */
2016-03-19 07:19:38 +03:00
smb_fname_cwd = synthetic_smb_fname ( talloc_tos ( ) ,
" . " ,
NULL ,
NULL ,
smb_dname - > flags ) ;
2013-04-15 13:02:19 +04:00
if ( smb_fname_cwd = = NULL ) {
2012-03-01 04:05:50 +04:00
goto out ;
}
ret = SMB_VFS_STAT ( conn , smb_fname_cwd ) ;
if ( ret ! = 0 ) {
goto out ;
}
if ( ! check_same_stat ( & smb_fname_cwd - > st , & priv_paths - > parent_name . st ) ) {
DEBUG ( 0 , ( " open_dir_with_privilege: stat mismatch between %s "
" and %s \n " ,
2016-02-27 03:35:17 +03:00
smb_dname - > base_name ,
2012-03-01 04:05:50 +04:00
smb_fname_str_dbg ( & priv_paths - > parent_name ) ) ) ;
goto out ;
}
2016-02-27 02:55:14 +03:00
dir_hnd = OpenDir ( NULL , conn , smb_fname_cwd , wcard , attr ) ;
2012-03-01 04:05:50 +04:00
out :
vfs_ChDir ( conn , saved_dir ) ;
return dir_hnd ;
}
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
const struct smb_filename * smb_dname ,
bool old_handle ,
bool expect_close ,
uint16_t spid ,
const char * wcard ,
bool wcard_has_wild ,
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 ;
struct smb_Dir * dir_hnd ;
2011-02-10 02:05:58 +03:00
if ( fsp & & fsp - > is_directory & & fsp - > fh - > fd ! = - 1 ) {
2016-02-27 03:35:17 +03:00
smb_dname = fsp - > fsp_name ;
2011-02-10 02:05:58 +03:00
}
2016-02-27 03:35:17 +03:00
DEBUG ( 5 , ( " dptr_create dir=%s \n " , smb_dname - > base_name ) ) ;
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
}
2011-02-10 03:31:06 +03:00
if ( fsp ) {
2011-11-04 21:51:29 +04:00
if ( ! ( fsp - > access_mask & SEC_DIR_LIST ) ) {
DEBUG ( 5 , ( " dptr_create: directory %s "
" not open for LIST access \n " ,
2016-02-27 03:35:17 +03:00
smb_dname - > base_name ) ) ;
2011-11-04 21:51:29 +04:00
return NT_STATUS_ACCESS_DENIED ;
}
2011-02-10 03:31:06 +03:00
dir_hnd = OpenDir_fsp ( NULL , conn , fsp , wcard , attr ) ;
} else {
2011-11-05 03:46:47 +04:00
int ret ;
2012-09-14 02:35:21 +04:00
bool backup_intent = ( req & & req - > priv_paths ) ;
2013-04-15 13:53:32 +04:00
NTSTATUS status ;
2016-02-27 03:35:17 +03:00
struct smb_filename * smb_dname_cp =
cp_smb_filename ( talloc_tos ( ) , smb_dname ) ;
2013-04-15 13:53:32 +04:00
2016-02-27 03:35:17 +03:00
if ( smb_dname_cp = = NULL ) {
2013-04-15 13:53:32 +04:00
return NT_STATUS_NO_MEMORY ;
2011-11-05 03:46:47 +04:00
}
2016-02-27 03:35:17 +03:00
2015-12-23 01:46:36 +03:00
if ( req ! = NULL & & req - > posix_pathnames ) {
2016-02-27 03:35:17 +03:00
ret = SMB_VFS_LSTAT ( conn , smb_dname_cp ) ;
2011-11-05 03:46:47 +04:00
} else {
2016-02-27 03:35:17 +03:00
ret = SMB_VFS_STAT ( conn , smb_dname_cp ) ;
2011-11-05 03:46:47 +04:00
}
if ( ret = = - 1 ) {
2016-02-27 03:35:17 +03:00
status = map_nt_error_from_unix ( errno ) ;
TALLOC_FREE ( smb_dname_cp ) ;
return status ;
2011-11-05 03:46:47 +04:00
}
2016-02-27 03:35:17 +03:00
if ( ! S_ISDIR ( smb_dname_cp - > st . st_ex_mode ) ) {
TALLOC_FREE ( smb_dname_cp ) ;
2011-11-05 03:46:47 +04:00
return NT_STATUS_NOT_A_DIRECTORY ;
}
status = smbd_check_access_rights ( conn ,
2016-02-27 03:35:17 +03:00
smb_dname_cp ,
2012-09-14 03:11:31 +04:00
backup_intent ,
2011-11-05 03:46:47 +04:00
SEC_DIR_LIST ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2016-02-27 03:35:17 +03:00
TALLOC_FREE ( smb_dname_cp ) ;
2011-11-05 03:46:47 +04:00
return status ;
}
2012-09-14 02:35:21 +04:00
if ( backup_intent ) {
2012-03-01 04:05:50 +04:00
dir_hnd = open_dir_with_privilege ( conn ,
req ,
2016-02-27 03:35:17 +03:00
smb_dname_cp ,
2012-03-01 04:05:50 +04:00
wcard ,
attr ) ;
} else {
2016-02-27 03:35:17 +03:00
dir_hnd = OpenDir ( NULL ,
conn ,
smb_dname_cp ,
wcard ,
attr ) ;
2012-03-01 04:05:50 +04:00
}
2016-02-27 03:35:17 +03:00
TALLOC_FREE ( smb_dname_cp ) ;
2007-01-17 05:09:37 +03:00
}
1996-05-04 11:50:46 +04:00
2005-02-01 03:28:20 +03:00
if ( ! dir_hnd ) {
2007-01-17 05:09:37 +03:00
return map_nt_error_from_unix ( errno ) ;
2005-02-01 03:28:20 +03:00
}
2011-03-18 02:16:54 +03:00
if ( sconn - > searches . dirhandles_open > = MAX_OPEN_DIRECTORIES ) {
2009-08-06 14:15:51 +04:00
dptr_idleoldest ( sconn ) ;
2007-01-17 05:09:37 +03:00
}
1999-12-13 16:27:58 +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
2016-02-27 03:35:17 +03:00
dptr - > smb_dname = cp_smb_filename ( dptr , smb_dname ) ;
if ( ! dptr - > smb_dname ) {
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 ;
}
dptr - > conn = conn ;
dptr - > dir_hnd = dir_hnd ;
dptr - > spid = spid ;
dptr - > expect_close = expect_close ;
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 ;
}
2015-12-23 01:46:36 +03:00
if ( ( req ! = NULL & & req - > posix_pathnames ) | |
( wcard [ 0 ] = = ' . ' & & wcard [ 1 ] = = 0 ) ) {
2011-11-09 18:59:22 +04:00
dptr - > has_wild = True ;
} else {
dptr - > has_wild = wcard_has_wild ;
}
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 ) {
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
/*
* Try and close the oldest handle not marked for
* expect close in the hope that the client has
* finished with that one .
*/
1996-05-04 11:50:46 +04:00
2009-08-06 14:15:51 +04:00
dptr_close_oldest ( sconn , true ) ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
/* Now try again... */
2011-03-18 02:16:54 +03:00
dptr - > dnum = bitmap_find ( sconn - > searches . dptr_bmap , 0 ) ;
2003-01-03 21:50:13 +03:00
if ( dptr - > dnum = = - 1 | | dptr - > dnum > 254 ) {
DEBUG ( 0 , ( " dptr_create: returned %d: Error - all old dirptrs in use ? \n " , dptr - > dnum ) ) ;
2012-02-25 05:16:08 +04:00
TALLOC_FREE ( dptr ) ;
2008-01-12 19:08:04 +03:00
TALLOC_FREE ( dir_hnd ) ;
2007-01-17 05:09:37 +03:00
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 ) {
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
/*
* Try and close the oldest handle close in the hope that
* the client has finished with that one . This will only
* happen in the case of the Win98 client bug where it leaks
* directory handles .
*/
1999-12-13 16:27:58 +03:00
2009-08-06 14:15:51 +04:00
dptr_close_oldest ( sconn , false ) ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
/* Now try again... */
2011-03-18 02:16:54 +03:00
dptr - > dnum = bitmap_find ( sconn - > searches . dptr_bmap , 255 ) ;
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
if ( dptr - > dnum = = - 1 | | dptr - > dnum < 255 ) {
DEBUG ( 0 , ( " dptr_create: returned %d: Error - all new dirptrs in use ? \n " , dptr - > dnum ) ) ;
2012-02-25 05:16:08 +04:00
TALLOC_FREE ( dptr ) ;
2008-01-12 19:08:04 +03:00
TALLOC_FREE ( dir_hnd ) ;
2007-01-17 05:09:37 +03:00
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 :
2003-01-03 21:50:13 +03:00
DEBUG ( 3 , ( " creating new dirptr %d for path %s, expect_close = %d \n " ,
2016-02-27 03:35:17 +03:00
dptr - > dnum ,
dptr - > smb_dname - > base_name ,
expect_close ) ) ;
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
{
2011-02-09 02:05:00 +03:00
if ( fsp - > dptr ) {
2013-04-11 03:29:03 +04:00
/*
* The destructor for the struct smb_Dir
* ( fsp - > dptr - > dir_hnd ) now handles
* all resource deallocation .
*/
2011-02-09 02:05:00 +03:00
dptr_close_internal ( fsp - > dptr ) ;
2013-04-26 21:47:41 +04:00
fsp - > dptr = NULL ;
2011-02-09 02:05:00 +03:00
}
2005-02-01 03:28:20 +03:00
}
void dptr_SeekDir ( struct dptr_struct * dptr , long offset )
{
SeekDir ( dptr - > dir_hnd , offset ) ;
}
long dptr_TellDir ( struct dptr_struct * dptr )
{
return TellDir ( dptr - > dir_hnd ) ;
}
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 ;
}
2005-02-01 21:33:50 +03:00
/****************************************************************************
Return the next visible file name , skipping veto ' d and invisible files .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-11-16 11:49:23 +03:00
static const char * dptr_normal_ReadDirName ( struct dptr_struct * dptr ,
long * poffset , SMB_STRUCT_STAT * pst ,
char * * ptalloced )
2005-02-01 03:28:20 +03:00
{
2005-02-01 21:33:50 +03:00
/* Normal search for the next file. */
2009-11-16 11:49:23 +03:00
const char * name ;
char * talloced = NULL ;
while ( ( name = ReadDirName ( dptr - > dir_hnd , poffset , pst , & talloced ) )
! = NULL ) {
2016-02-27 03:35:17 +03:00
if ( is_visible_file ( dptr - > conn ,
dptr - > smb_dname - > base_name ,
name ,
pst ,
true ) ) {
2009-11-16 11:49:23 +03:00
* ptalloced = talloced ;
2005-02-01 21:33:50 +03:00
return name ;
}
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2005-02-01 21:33:50 +03:00
}
return NULL ;
}
/****************************************************************************
Return the next visible file name , skipping veto ' d and invisible files .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2014-07-03 11:57:02 +04:00
static char * dptr_ReadDirName ( TALLOC_CTX * ctx ,
struct dptr_struct * dptr ,
long * poffset ,
SMB_STRUCT_STAT * pst )
2005-02-01 21:33:50 +03:00
{
2009-11-15 12:46:23 +03:00
struct smb_filename smb_fname_base ;
2009-01-23 07:18:56 +03:00
char * name = NULL ;
2009-11-16 11:49:23 +03:00
const char * name_temp = NULL ;
char * talloced = NULL ;
2009-01-23 07:18:56 +03:00
char * pathreal = NULL ;
2009-05-02 04:28:38 +04:00
char * found_name = NULL ;
int ret ;
2005-06-03 09:35:04 +04:00
SET_STAT_INVALID ( * pst ) ;
2005-03-03 05:04:36 +03:00
2009-01-23 07:18:56 +03:00
if ( dptr - > has_wild | | dptr - > did_stat ) {
2009-11-16 11:49:23 +03:00
name_temp = dptr_normal_ReadDirName ( dptr , poffset , pst ,
& talloced ) ;
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
}
2009-01-23 07:18:56 +03:00
/* If poffset is -1 then we know we returned this name before and we
* have no wildcards . We ' re at the end of the directory . */
2005-07-22 00:24:21 +04:00
if ( * poffset = = END_OF_DIRECTORY_OFFSET ) {
2005-03-03 05:04:36 +03:00
return NULL ;
}
2009-01-23 07:18:56 +03:00
/* We know the stored wcard contains no wildcard characters.
* See if we can match with a stat call . If we can ' t , then set
* did_stat to true to ensure we only do this once and keep
* searching . */
dptr - > did_stat = true ;
/* First check if it should be visible. */
2016-02-27 03:35:17 +03:00
if ( ! is_visible_file ( dptr - > conn ,
dptr - > smb_dname - > base_name ,
dptr - > wcard ,
pst ,
true ) ) {
2009-01-23 07:18:56 +03:00
/* This only returns false if the file was found, but
is explicitly not visible . Set us to end of
directory , but return NULL as we know we can ' t ever
find it . */
goto ret ;
}
2005-02-01 21:33:50 +03:00
2009-01-23 07:18:56 +03:00
if ( VALID_STAT ( * pst ) ) {
2009-05-12 02:39:05 +04:00
name = talloc_strdup ( ctx , dptr - > wcard ) ;
2009-01-23 07:18:56 +03:00
goto ret ;
}
2005-02-01 21:33:50 +03:00
2009-01-23 07:18:56 +03:00
pathreal = talloc_asprintf ( ctx ,
" %s/%s " ,
2016-02-27 03:35:17 +03:00
dptr - > smb_dname - > base_name ,
2009-01-23 07:18:56 +03:00
dptr - > wcard ) ;
if ( ! pathreal )
return NULL ;
2005-02-01 21:33:50 +03:00
2009-06-23 02:26:56 +04:00
/* Create an smb_filename with stream_name == NULL. */
2015-02-23 14:07:32 +03:00
smb_fname_base = ( struct smb_filename ) { . base_name = pathreal } ;
2009-06-23 02:26:56 +04:00
2009-11-15 12:46:23 +03:00
if ( SMB_VFS_STAT ( dptr - > conn , & smb_fname_base ) = = 0 ) {
* pst = smb_fname_base . st ;
2009-05-12 02:39:05 +04:00
name = talloc_strdup ( ctx , dptr - > wcard ) ;
2009-01-23 07:18:56 +03:00
goto clean ;
} else {
/* If we get any other error than ENOENT or ENOTDIR
then the file exists we just can ' t stat it . */
if ( errno ! = ENOENT & & errno ! = ENOTDIR ) {
2009-05-12 02:39:05 +04:00
name = talloc_strdup ( ctx , dptr - > wcard ) ;
2009-01-23 07:18:56 +03:00
goto clean ;
2006-09-15 13:06:36 +04:00
}
2009-01-23 07:18:56 +03:00
}
2006-09-15 13:06:36 +04:00
2009-01-23 07:18:56 +03:00
/* Stat failed. We know this is authoratiative if we are
* providing case sensitive semantics or the underlying
* filesystem is case sensitive .
*/
if ( dptr - > conn - > case_sensitive | |
! ( dptr - > conn - > fs_capabilities & FILE_CASE_SENSITIVE_SEARCH ) )
{
goto clean ;
}
2007-09-13 01:48:20 +04:00
2009-05-02 04:28:38 +04:00
/*
* Try case - insensitive stat if the fs has the ability . This avoids
* scanning the whole directory .
*/
2016-02-27 03:35:17 +03:00
ret = SMB_VFS_GET_REAL_FILENAME ( dptr - > conn ,
dptr - > smb_dname - > base_name ,
dptr - > wcard ,
ctx ,
& found_name ) ;
2009-05-02 04:28:38 +04:00
if ( ret = = 0 ) {
name = found_name ;
goto clean ;
} else if ( errno = = ENOENT ) {
/* The case-insensitive lookup was authoritative. */
goto clean ;
}
2009-01-23 07:18:56 +03:00
TALLOC_FREE ( pathreal ) ;
2006-09-15 13:06:36 +04:00
2009-11-16 11:49:23 +03:00
name_temp = dptr_normal_ReadDirName ( dptr , poffset , pst , & talloced ) ;
if ( name_temp = = NULL ) {
return NULL ;
}
if ( talloced ! = NULL ) {
return talloc_move ( ctx , & talloced ) ;
}
return talloc_strdup ( ctx , name_temp ) ;
2009-01-23 07:18:56 +03:00
clean :
TALLOC_FREE ( pathreal ) ;
ret :
/* We need to set the underlying dir_hnd offset to -1
* also as this function is usually called with the
* output from TellDir . */
dptr - > dir_hnd - > offset = * poffset = END_OF_DIRECTORY_OFFSET ;
return name ;
2005-02-01 21:33:50 +03:00
}
/****************************************************************************
Search for a file by name , skipping veto ' ed and not visible files .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool dptr_SearchDir ( struct dptr_struct * dptr , const char * name , long * poffset , SMB_STRUCT_STAT * pst )
2005-02-01 21:33:50 +03:00
{
2005-06-03 09:35:04 +04:00
SET_STAT_INVALID ( * pst ) ;
2005-03-21 21:10:21 +03:00
2005-07-22 00:24:21 +04:00
if ( ! dptr - > has_wild & & ( dptr - > dir_hnd - > offset = = END_OF_DIRECTORY_OFFSET ) ) {
2005-03-21 21:10:21 +03:00
/* This is a singleton directory and we're already at the end. */
2005-07-22 00:24:21 +04:00
* poffset = END_OF_DIRECTORY_OFFSET ;
2005-03-21 21:10:21 +03:00
return False ;
}
2006-06-27 03:36:03 +04:00
return SearchDir ( dptr - > dir_hnd , name , poffset ) ;
2005-02-01 03:28:20 +03:00
}
2009-02-03 08:37:51 +03:00
/****************************************************************************
Initialize variables & state data at the beginning of all search SMB requests .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void dptr_init_search_op ( struct dptr_struct * dptr )
{
2009-02-14 13:42:05 +03:00
SMB_VFS_INIT_SEARCH_OP ( dptr - > conn , dptr - > dir_hnd - > dir ) ;
2009-02-03 08:37:51 +03:00
}
2014-01-12 02:48:00 +04:00
/****************************************************************************
Map a native directory offset to a 32 - bit cookie .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static uint32_t map_dir_offset_to_wire ( struct dptr_struct * dptr , long offset )
{
2014-01-12 03:45:48 +04:00
DATA_BLOB key ;
DATA_BLOB val ;
2014-01-12 02:59:00 +04:00
if ( offset = = END_OF_DIRECTORY_OFFSET ) {
return WIRE_END_OF_DIRECTORY_OFFSET ;
} else if ( offset = = START_OF_DIRECTORY_OFFSET ) {
return WIRE_START_OF_DIRECTORY_OFFSET ;
} else if ( offset = = DOT_DOT_DIRECTORY_OFFSET ) {
return WIRE_DOT_DOT_DIRECTORY_OFFSET ;
}
2014-01-12 03:45:48 +04:00
if ( sizeof ( long ) = = 4 ) {
/* 32-bit machine. We can cheat... */
return ( uint32_t ) offset ;
}
if ( dptr - > dptr_cache = = NULL ) {
/* Lazy initialize cache. */
dptr - > dptr_cache = memcache_init ( dptr , 0 ) ;
if ( dptr - > dptr_cache = = NULL ) {
return WIRE_END_OF_DIRECTORY_OFFSET ;
}
} else {
/* Have we seen this offset before ? */
key . data = ( void * ) & offset ;
key . length = sizeof ( offset ) ;
if ( memcache_lookup ( dptr - > dptr_cache ,
SMB1_SEARCH_OFFSET_MAP ,
key ,
& val ) ) {
uint32_t wire_offset ;
SMB_ASSERT ( val . length = = sizeof ( wire_offset ) ) ;
memcpy ( & wire_offset , val . data , sizeof ( wire_offset ) ) ;
DEBUG ( 10 , ( " found wire %u <-> offset %ld \n " ,
( unsigned int ) wire_offset ,
( long ) offset ) ) ;
return wire_offset ;
}
}
/* Allocate a new wire cookie. */
do {
dptr - > counter + + ;
} while ( dptr - > counter = = WIRE_START_OF_DIRECTORY_OFFSET | |
dptr - > counter = = WIRE_END_OF_DIRECTORY_OFFSET | |
dptr - > counter = = WIRE_DOT_DOT_DIRECTORY_OFFSET ) ;
/* Store it in the cache. */
key . data = ( void * ) & offset ;
key . length = sizeof ( offset ) ;
val . data = ( void * ) & dptr - > counter ;
val . length = sizeof ( dptr - > counter ) ; /* MUST BE uint32_t ! */
memcache_add ( dptr - > dptr_cache ,
SMB1_SEARCH_OFFSET_MAP ,
key ,
val ) ;
/* And the reverse mapping for lookup from
map_wire_to_dir_offset ( ) . */
memcache_add ( dptr - > dptr_cache ,
SMB1_SEARCH_OFFSET_MAP ,
val ,
key ) ;
DEBUG ( 10 , ( " stored wire %u <-> offset %ld \n " ,
( unsigned int ) dptr - > counter ,
( long ) offset ) ) ;
return dptr - > counter ;
2014-01-12 02:48:00 +04:00
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
Fill the 5 byte server reserved dptr field .
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 dptr_fill ( struct smbd_server_connection * sconn ,
char * buf1 , unsigned int key )
1996-05-04 11:50:46 +04:00
{
2003-01-03 21:50:13 +03:00
unsigned char * buf = ( unsigned char * ) buf1 ;
2009-08-06 14:15:51 +04:00
struct dptr_struct * dptr = dptr_get ( sconn , key , false ) ;
2014-01-12 02:36:17 +04:00
uint32_t wire_offset ;
2005-02-01 03:28:20 +03:00
if ( ! dptr ) {
2003-01-03 21:50:13 +03:00
DEBUG ( 1 , ( " filling null dirptr %d \n " , key ) ) ;
return ( False ) ;
}
2014-01-12 02:48:00 +04:00
wire_offset = map_dir_offset_to_wire ( dptr , TellDir ( dptr - > dir_hnd ) ) ;
2003-01-03 21:50:13 +03:00
DEBUG ( 6 , ( " fill on key %u dirptr 0x%lx now at %d \n " , key ,
2014-01-12 02:36:17 +04:00
( long ) dptr - > dir_hnd , ( int ) wire_offset ) ) ;
2003-01-03 21:50:13 +03:00
buf [ 0 ] = key ;
2014-01-12 02:36:17 +04:00
SIVAL ( buf , 1 , wire_offset ) ;
2003-01-03 21:50:13 +03:00
return ( True ) ;
1996-05-04 11:50:46 +04:00
}
2014-01-12 03:04:38 +04:00
/****************************************************************************
Map a 32 - bit wire cookie to a native directory offset .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static long map_wire_to_dir_offset ( struct dptr_struct * dptr , uint32_t wire_offset )
{
2014-01-12 03:45:48 +04:00
DATA_BLOB key ;
DATA_BLOB val ;
2014-01-12 03:04:38 +04:00
if ( wire_offset = = WIRE_END_OF_DIRECTORY_OFFSET ) {
return END_OF_DIRECTORY_OFFSET ;
} else if ( wire_offset = = WIRE_START_OF_DIRECTORY_OFFSET ) {
return START_OF_DIRECTORY_OFFSET ;
} else if ( wire_offset = = WIRE_DOT_DOT_DIRECTORY_OFFSET ) {
return DOT_DOT_DIRECTORY_OFFSET ;
}
2014-01-12 03:45:48 +04:00
if ( sizeof ( long ) = = 4 ) {
/* 32-bit machine. We can cheat... */
return ( long ) wire_offset ;
}
if ( dptr - > dptr_cache = = NULL ) {
/* Logic error, cache should be initialized. */
return END_OF_DIRECTORY_OFFSET ;
}
key . data = ( void * ) & wire_offset ;
key . length = sizeof ( wire_offset ) ;
if ( memcache_lookup ( dptr - > dptr_cache ,
SMB1_SEARCH_OFFSET_MAP ,
key ,
& val ) ) {
/* Found mapping. */
long offset ;
SMB_ASSERT ( val . length = = sizeof ( offset ) ) ;
memcpy ( & offset , val . data , sizeof ( offset ) ) ;
DEBUG ( 10 , ( " lookup wire %u <-> offset %ld \n " ,
( unsigned int ) wire_offset ,
( long ) offset ) ) ;
return offset ;
}
return END_OF_DIRECTORY_OFFSET ;
2014-01-12 03:04:38 +04:00
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
Fetch the dir ptr and seek it given the 5 byte server field .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2009-08-06 14:15:51 +04:00
struct dptr_struct * dptr_fetch ( struct smbd_server_connection * sconn ,
char * buf , int * num )
1996-05-04 11:50:46 +04:00
{
2003-01-03 21:50:13 +03:00
unsigned int key = * ( unsigned char * ) buf ;
2009-08-06 14:15:51 +04:00
struct dptr_struct * dptr = dptr_get ( sconn , key , false ) ;
2014-01-12 02:36:17 +04:00
uint32_t wire_offset ;
2005-05-01 13:30:18 +04:00
long seekoff ;
2003-01-03 21:50:13 +03:00
2005-02-01 03:28:20 +03:00
if ( ! dptr ) {
2003-01-03 21:50:13 +03:00
DEBUG ( 3 , ( " fetched null dirptr %d \n " , key ) ) ;
return ( NULL ) ;
}
* num = key ;
2014-01-12 02:36:17 +04:00
wire_offset = IVAL ( buf , 1 ) ;
2014-01-12 03:04:38 +04:00
seekoff = map_wire_to_dir_offset ( dptr , wire_offset ) ;
2005-05-01 13:30:18 +04:00
SeekDir ( dptr - > dir_hnd , seekoff ) ;
2003-01-03 21:50:13 +03:00
DEBUG ( 3 , ( " fetching dirptr %d for path %s at offset %d \n " ,
2016-02-27 03:35:17 +03:00
key , dptr - > smb_dname - > base_name , ( int ) seekoff ) ) ;
2005-02-01 03:28:20 +03:00
return ( dptr ) ;
1996-05-04 11:50:46 +04:00
}
/****************************************************************************
1999-12-13 16:27:58 +03:00
Fetch the dir ptr .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2009-08-06 14:15:51 +04:00
struct dptr_struct * dptr_fetch_lanman2 ( struct smbd_server_connection * sconn ,
int dptr_num )
1996-05-04 11:50:46 +04:00
{
2009-08-06 14:15:51 +04:00
struct dptr_struct * dptr = dptr_get ( sconn , dptr_num , false ) ;
2003-01-03 21:50:13 +03:00
2005-02-01 03:28:20 +03:00
if ( ! dptr ) {
2003-01-03 21:50:13 +03:00
DEBUG ( 3 , ( " fetched null dirptr %d \n " , dptr_num ) ) ;
return ( NULL ) ;
}
2016-02-27 03:35:17 +03:00
DEBUG ( 3 , ( " fetching dirptr %d for path %s \n " ,
dptr_num ,
dptr - > smb_dname - > base_name ) ) ;
2005-02-01 03:28:20 +03:00
return ( dptr ) ;
1996-05-04 11:50:46 +04:00
}
2007-10-19 04:40:25 +04:00
static bool mangle_mask_match ( connection_struct * conn ,
2007-09-12 03:57:59 +04:00
const char * filename ,
const char * mask )
2002-07-15 14:35:28 +04:00
{
2007-09-08 00:57:01 +04:00
char mname [ 13 ] ;
if ( ! name_to_8_3 ( filename , mname , False , conn - > params ) ) {
return False ;
}
return mask_match_search ( mname , mask , False ) ;
2002-07-15 14:35:28 +04:00
}
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 ,
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 ,
struct smb_filename * smb_fname ,
uint32_t * _mode ) ,
void * private_data ,
char * * _fname ,
struct smb_filename * * _smb_fname ,
uint32_t * _mode ,
long * _prev_offset )
{
connection_struct * conn = dirptr - > conn ;
2013-03-22 01:00:06 +04:00
size_t slashlen ;
size_t pathlen ;
2016-02-27 03:35:17 +03:00
const char * dpath = dirptr - > smb_dname - > base_name ;
bool dirptr_path_is_dot = ISDOT ( dpath ) ;
2009-08-06 22:53:13 +04:00
* _smb_fname = NULL ;
* _mode = 0 ;
2016-02-27 03:35:17 +03:00
pathlen = strlen ( dpath ) ;
slashlen = ( dpath [ pathlen - 1 ] ! = ' / ' ) ? 1 : 0 ;
2009-08-06 22:53:13 +04:00
while ( true ) {
long cur_offset ;
long prev_offset ;
2014-07-03 12:00:13 +04:00
SMB_STRUCT_STAT sbuf = { 0 } ;
2009-08-06 22:53:13 +04:00
char * dname = NULL ;
bool isdots ;
char * fname = NULL ;
char * pathreal = NULL ;
2009-11-15 12:46:23 +03:00
struct smb_filename smb_fname ;
2009-08-06 22:53:13 +04:00
uint32_t mode = 0 ;
bool ok ;
cur_offset = dptr_TellDir ( dirptr ) ;
prev_offset = cur_offset ;
dname = dptr_ReadDirName ( ctx , dirptr , & cur_offset , & sbuf ) ;
DEBUG ( 6 , ( " smbd_dirptr_get_entry: dirptr 0x%lx now at offset %ld \n " ,
( long ) dirptr , cur_offset ) ) ;
if ( dname = = NULL ) {
return false ;
}
isdots = ( ISDOT ( dname ) | | ISDOTDOT ( dname ) ) ;
if ( dont_descend & & ! isdots ) {
TALLOC_FREE ( dname ) ;
continue ;
}
/*
* 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 ;
}
2013-03-22 01:00:06 +04:00
/*
* This used to be
* pathreal = talloc_asprintf ( ctx , " %s%s%s " , dirptr - > path ,
* needslash ? " / " : " " , dname ) ;
* but this was measurably slower than doing the memcpy .
*/
pathreal = talloc_array (
ctx , char ,
pathlen + slashlen + talloc_get_size ( dname ) ) ;
2009-08-06 22:53:13 +04:00
if ( ! pathreal ) {
TALLOC_FREE ( dname ) ;
TALLOC_FREE ( fname ) ;
return false ;
}
2015-04-15 23:53:09 +03:00
/*
* We don ' t want to pass . / xxx to modules below us so don ' t
* add the path if it is just . by itself .
*/
if ( dirptr_path_is_dot ) {
memcpy ( pathreal , dname , talloc_get_size ( dname ) ) ;
} else {
2016-02-27 03:35:17 +03:00
memcpy ( pathreal , dpath , pathlen ) ;
2015-04-15 23:53:09 +03:00
pathreal [ pathlen ] = ' / ' ;
memcpy ( pathreal + slashlen + pathlen , dname ,
talloc_get_size ( dname ) ) ;
}
2013-03-22 01:00:06 +04:00
2009-08-06 22:53:13 +04:00
/* Create smb_fname with NULL stream_name. */
2015-02-23 14:08:30 +03:00
smb_fname = ( struct smb_filename ) {
. base_name = pathreal , . st = sbuf
} ;
2009-08-06 22:53:13 +04:00
2009-11-15 12:46:23 +03:00
ok = mode_fn ( ctx , private_data , & smb_fname , & mode ) ;
2009-08-06 22:53:13 +04:00
if ( ! ok ) {
TALLOC_FREE ( dname ) ;
TALLOC_FREE ( fname ) ;
2009-11-15 12:46:23 +03:00
TALLOC_FREE ( pathreal ) ;
2009-08-06 22:53:13 +04:00
continue ;
}
2013-11-13 03:17:26 +04:00
if ( ! dir_check_ftype ( mode , dirtype ) ) {
2009-08-06 22:53:13 +04:00
DEBUG ( 5 , ( " [%s] attribs 0x%x didn't match 0x%x \n " ,
fname , ( unsigned int ) mode , ( unsigned int ) dirtype ) ) ;
TALLOC_FREE ( dname ) ;
TALLOC_FREE ( fname ) ;
2009-11-15 12:46:23 +03:00
TALLOC_FREE ( pathreal ) ;
2009-08-06 22:53:13 +04:00
continue ;
}
if ( ask_sharemode ) {
struct timespec write_time_ts ;
struct file_id fileid ;
fileid = vfs_file_id_from_sbuf ( conn ,
2009-11-15 12:46:23 +03:00
& smb_fname . st ) ;
2011-01-26 00:57:38 +03:00
get_file_infos ( fileid , 0 , NULL , & write_time_ts ) ;
2009-08-06 22:53:13 +04:00
if ( ! null_timespec ( write_time_ts ) ) {
2009-11-15 12:46:23 +03:00
update_stat_ex_mtime ( & smb_fname . st ,
2009-08-06 22:53:13 +04:00
write_time_ts ) ;
}
}
DEBUG ( 3 , ( " smbd_dirptr_get_entry mask=[%s] found %s "
" fname=%s (%s) \n " ,
2009-11-15 12:46:23 +03:00
mask , smb_fname_str_dbg ( & smb_fname ) ,
2009-08-06 22:53:13 +04:00
dname , fname ) ) ;
DirCacheAdd ( dirptr - > dir_hnd , dname , cur_offset ) ;
TALLOC_FREE ( dname ) ;
2013-04-11 18:22:38 +04:00
* _smb_fname = cp_smb_filename ( ctx , & smb_fname ) ;
2009-11-15 12:46:23 +03:00
TALLOC_FREE ( pathreal ) ;
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 ;
* _prev_offset = prev_offset ;
return true ;
}
return false ;
}
1996-05-04 11:50:46 +04:00
/****************************************************************************
1999-12-13 16:27:58 +03:00
Get an 8.3 directory entry .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2009-08-07 10:54:06 +04:00
static bool smbd_dirptr_8_3_match_fn ( TALLOC_CTX * ctx ,
void * private_data ,
const char * dname ,
const char * mask ,
char * * _fname )
1996-05-04 11:50:46 +04:00
{
2009-08-07 10:54:06 +04:00
connection_struct * conn = ( connection_struct * ) private_data ;
if ( ( strcmp ( mask , " *.* " ) = = 0 ) | |
mask_match_search ( dname , mask , false ) | |
mangle_mask_match ( conn , dname , mask ) ) {
char mname [ 13 ] ;
const char * fname ;
2014-08-27 03:39:56 +04:00
/*
* Ensure we can push the original name as UCS2 . If
* not , then just don ' t return this name .
*/
NTSTATUS status ;
size_t ret_len = 0 ;
size_t len = ( strlen ( dname ) + 2 ) * 4 ; /* Allow enough space. */
uint8_t * tmp = talloc_array ( talloc_tos ( ) ,
2015-05-03 07:01:14 +03:00
uint8_t ,
2014-08-27 03:39:56 +04:00
len ) ;
status = srvstr_push ( NULL ,
FLAGS2_UNICODE_STRINGS ,
tmp ,
dname ,
len ,
STR_TERMINATE ,
& ret_len ) ;
TALLOC_FREE ( tmp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return false ;
}
2009-08-07 10:54:06 +04:00
if ( ! mangle_is_8_3 ( dname , false , conn - > params ) ) {
bool ok = name_to_8_3 ( dname , mname , false ,
conn - > params ) ;
if ( ! ok ) {
2009-07-08 23:24:03 +04:00
return false ;
}
2009-08-07 10:54:06 +04:00
fname = mname ;
} else {
fname = dname ;
}
2009-07-08 23:24:03 +04:00
2009-08-07 10:54:06 +04:00
* _fname = talloc_strdup ( ctx , fname ) ;
if ( * _fname = = NULL ) {
return false ;
}
1996-05-04 11:50:46 +04:00
2009-08-07 10:54:06 +04:00
return true ;
}
2008-04-07 11:21:19 +04:00
2009-08-07 10:54:06 +04:00
return false ;
}
2008-03-12 17:39:38 +03:00
2009-08-07 10:54:06 +04:00
static bool smbd_dirptr_8_3_mode_fn ( TALLOC_CTX * ctx ,
void * private_data ,
struct smb_filename * smb_fname ,
uint32_t * _mode )
{
connection_struct * conn = ( connection_struct * ) private_data ;
if ( ! VALID_STAT ( smb_fname - > st ) ) {
if ( ( SMB_VFS_STAT ( conn , smb_fname ) ) ! = 0 ) {
DEBUG ( 5 , ( " smbd_dirptr_8_3_mode_fn: "
" Couldn't stat [%s]. Error "
" = %s \n " ,
smb_fname_str_dbg ( smb_fname ) ,
strerror ( errno ) ) ) ;
return false ;
}
}
1996-05-04 11:50:46 +04:00
2009-08-07 10:54:06 +04:00
* _mode = dos_mode ( conn , smb_fname ) ;
return true ;
}
2006-04-08 09:00:04 +04:00
2009-08-07 10:54:06 +04:00
bool get_dir_entry ( TALLOC_CTX * ctx ,
2009-08-07 11:31:45 +04:00
struct dptr_struct * dirptr ,
2009-08-07 10:54:06 +04:00
const char * mask ,
uint32_t dirtype ,
char * * _fname ,
2012-04-05 08:53:08 +04:00
off_t * _size ,
2009-08-07 10:54:06 +04:00
uint32_t * _mode ,
struct timespec * _date ,
bool check_descend ,
bool ask_sharemode )
{
2009-08-07 11:31:45 +04:00
connection_struct * conn = dirptr - > conn ;
2009-08-07 10:54:06 +04:00
char * fname = NULL ;
struct smb_filename * smb_fname = NULL ;
uint32_t mode = 0 ;
long prev_offset ;
bool ok ;
2007-09-13 01:48:20 +04:00
2009-08-07 10:54:06 +04:00
ok = smbd_dirptr_get_entry ( ctx ,
2009-08-07 11:31:45 +04:00
dirptr ,
2009-08-07 10:54:06 +04:00
mask ,
dirtype ,
check_descend ,
ask_sharemode ,
smbd_dirptr_8_3_match_fn ,
smbd_dirptr_8_3_mode_fn ,
conn ,
& fname ,
& smb_fname ,
& mode ,
& prev_offset ) ;
if ( ! ok ) {
return false ;
2003-01-03 21:50:13 +03:00
}
1996-05-04 11:50:46 +04:00
2009-08-07 10:54:06 +04:00
* _fname = talloc_move ( ctx , & fname ) ;
* _size = smb_fname - > st . st_ex_size ;
* _mode = mode ;
* _date = smb_fname - > st . st_ex_mtime ;
TALLOC_FREE ( smb_fname ) ;
return true ;
2003-01-03 21:50:13 +03:00
}
1996-05-04 11:50:46 +04:00
2001-04-16 19:16:31 +04:00
/*******************************************************************
2002-09-25 19:19:00 +04:00
Check to see if a user can read a file . This is only approximate ,
it is used as part of the " hide unreadable " option . Don ' t
use it for anything security sensitive .
2001-04-16 19:16:31 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-12-17 22:16:22 +03:00
2009-06-23 02:26:56 +04:00
static bool user_can_read_file ( connection_struct * conn ,
struct smb_filename * smb_fname )
2001-04-16 19:16:31 +04:00
{
2015-10-14 02:49:41 +03:00
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 ;
2002-07-15 14:35:28 +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-07-15 14:35:28 +04:00
*/
2010-03-15 22:24:06 +03:00
if ( get_current_uid ( conn ) = = ( uid_t ) 0 ) {
2002-07-15 14:35:28 +04:00
return True ;
2005-07-08 08:51:27 +04:00
}
2002-07-15 14:35:28 +04:00
2015-10-14 02:49:41 +03:00
/*
* We can ' t directly use smbd_check_access_rights ( )
* 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 & ~ ( conn - > share_access ) ;
if ( rejected_share_access ) {
DEBUG ( 10 , ( " rejected share access 0x%x "
" on %s (0x%x) \n " ,
( unsigned int ) access_mask ,
smb_fname_str_dbg ( smb_fname ) ,
( unsigned int ) rejected_share_access ) ) ;
return false ;
}
status = SMB_VFS_GET_NT_ACL ( conn ,
2016-02-12 21:30:10 +03:00
smb_fname ,
2015-10-14 02:49:41 +03:00
( SECINFO_OWNER |
SECINFO_GROUP |
SECINFO_DACL ) ,
talloc_tos ( ) ,
& sd ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 10 , ( " Could not get acl "
" on %s: %s \n " ,
smb_fname_str_dbg ( smb_fname ) ,
nt_errstr ( status ) ) ) ;
return false ;
}
status = se_file_access_check ( sd ,
get_current_nttok ( conn ) ,
2012-09-14 03:11:31 +04:00
false ,
2015-10-14 02:49:41 +03:00
access_mask ,
& rejected_mask ) ;
TALLOC_FREE ( sd ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_ACCESS_DENIED ) ) {
DEBUG ( 10 , ( " rejected bits 0x%x read access for %s \n " ,
( unsigned int ) rejected_mask ,
smb_fname_str_dbg ( smb_fname ) ) ) ;
return false ;
}
return true ;
2001-04-16 19:16:31 +04:00
}
2002-08-17 19:27:10 +04:00
/*******************************************************************
2002-09-25 19:19:00 +04:00
Check to see if a user can write a file ( and only files , we do not
check dirs on this one ) . This is only approximate ,
it is used as part of the " hide unwriteable " option . Don ' t
use it for anything security sensitive .
2002-08-17 19:27:10 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-06-26 05:19:09 +04:00
static bool user_can_write_file ( connection_struct * conn ,
const struct smb_filename * smb_fname )
2002-08-17 19:27:10 +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-08-17 19:27:10 +04:00
*/
2010-03-15 22:24:06 +03:00
if ( get_current_uid ( conn ) = = ( uid_t ) 0 ) {
2002-08-17 19:27:10 +04:00
return True ;
2005-07-08 08:51:27 +04:00
}
2002-08-17 19:27:10 +04:00
2009-06-26 05:19:09 +04:00
SMB_ASSERT ( VALID_STAT ( smb_fname - > st ) ) ;
2002-08-17 19:27:10 +04:00
2005-07-08 08:51:27 +04:00
/* Pseudo-open the file */
2002-08-17 19:27:10 +04:00
2009-06-26 05:19:09 +04:00
if ( S_ISDIR ( smb_fname - > st . st_ex_mode ) ) {
2002-08-17 19:27:10 +04:00
return True ;
2007-10-13 23:06:49 +04:00
}
2002-08-17 19:27:10 +04:00
2009-06-26 05:19:09 +04:00
return can_write_to_file ( conn , smb_fname ) ;
2002-08-17 19:27:10 +04:00
}
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 ;
}
2005-02-01 21:33:50 +03:00
/*******************************************************************
2009-01-23 07:18:56 +03:00
Should the file be seen by the client ?
NOTE : A successful return is no guarantee of the file ' s existence .
2005-02-01 21:33:50 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-01-23 07:18:56 +03:00
bool is_visible_file ( connection_struct * conn , const char * dir_path ,
const char * name , SMB_STRUCT_STAT * pst , bool use_veto )
2005-02-01 21:33:50 +03:00
{
2014-02-04 06:08:58 +04:00
bool hide_unreadable = lp_hide_unreadable ( SNUM ( conn ) ) ;
2014-02-04 06:08:59 +04:00
bool hide_unwriteable = lp_hide_unwriteable_files ( SNUM ( conn ) ) ;
2007-10-19 04:40:25 +04:00
bool hide_special = lp_hide_special_files ( SNUM ( conn ) ) ;
2009-06-23 02:26:56 +04:00
char * entry = NULL ;
struct smb_filename * smb_fname_base = NULL ;
bool ret = false ;
2005-02-01 21:33:50 +03:00
if ( ( strcmp ( " . " , name ) = = 0 ) | | ( strcmp ( " .. " , name ) = = 0 ) ) {
return True ; /* . and .. are always visible. */
}
/* If it's a vetoed file, pretend it doesn't even exist */
2009-11-23 18:33:53 +03:00
if ( use_veto & & IS_VETO_PATH ( conn , name ) ) {
2006-06-27 03:36:03 +04:00
DEBUG ( 10 , ( " is_visible_file: file %s is vetoed. \n " , name ) ) ;
2005-02-01 21:33:50 +03:00
return False ;
}
if ( hide_unreadable | | hide_unwriteable | | hide_special ) {
2009-06-18 22:38:42 +04:00
entry = talloc_asprintf ( talloc_tos ( ) , " %s/%s " , dir_path , name ) ;
2009-06-23 02:26:56 +04:00
if ( ! entry ) {
ret = false ;
goto out ;
2005-02-01 21:33:50 +03:00
}
2006-12-29 23:39:53 +03:00
2009-06-23 02:26:56 +04:00
/* Create an smb_filename with stream_name == NULL. */
2016-03-19 07:19:38 +03:00
smb_fname_base = synthetic_smb_fname ( talloc_tos ( ) ,
entry ,
NULL ,
pst ,
0 ) ;
2013-04-15 13:54:46 +04:00
if ( smb_fname_base = = NULL ) {
2009-06-23 02:26:56 +04:00
ret = false ;
goto out ;
2006-12-29 23:39:53 +03:00
}
2007-12-23 01:55:37 +03:00
/* If the file name 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 .
*/
2009-06-26 05:19:09 +04:00
if ( ! VALID_STAT ( * pst ) ) {
if ( SMB_VFS_STAT ( conn , smb_fname_base ) ! = 0 ) {
ret = true ;
goto out ;
}
2015-08-12 19:32:54 +03:00
* pst = smb_fname_base - > st ;
2007-12-23 01:55:37 +03:00
}
2005-02-01 21:33:50 +03:00
/* Honour _hide unreadable_ option */
2009-06-23 02:26:56 +04:00
if ( hide_unreadable & &
! user_can_read_file ( conn , smb_fname_base ) ) {
2009-01-23 07:18:56 +03:00
DEBUG ( 10 , ( " is_visible_file: file %s is unreadable. \n " ,
entry ) ) ;
2009-06-23 02:26:56 +04:00
ret = false ;
goto out ;
2005-02-01 21:33:50 +03:00
}
/* Honour _hide unwriteable_ option */
2009-06-26 05:19:09 +04:00
if ( hide_unwriteable & & ! user_can_write_file ( conn ,
smb_fname_base ) ) {
2009-01-23 07:18:56 +03:00
DEBUG ( 10 , ( " is_visible_file: file %s is unwritable. \n " ,
entry ) ) ;
2009-06-23 02:26:56 +04:00
ret = false ;
goto out ;
2005-02-01 21:33:50 +03:00
}
/* Honour _hide_special_ option */
2009-06-26 05:19:09 +04:00
if ( hide_special & & file_is_special ( conn , smb_fname_base ) ) {
2009-01-23 07:18:56 +03:00
DEBUG ( 10 , ( " is_visible_file: file %s is special. \n " ,
entry ) ) ;
2009-06-23 02:26:56 +04:00
ret = false ;
goto out ;
2005-02-01 21:33:50 +03:00
}
}
2009-06-23 02:26:56 +04:00
ret = true ;
out :
TALLOC_FREE ( smb_fname_base ) ;
TALLOC_FREE ( entry ) ;
return ret ;
2005-02-01 21:33:50 +03:00
}
2008-01-12 19:08:04 +03:00
static int smb_Dir_destructor ( struct smb_Dir * dirp )
{
2013-04-11 03:24:15 +04:00
if ( dirp - > dir ! = NULL ) {
SMB_VFS_CLOSEDIR ( dirp - > conn , dirp - > dir ) ;
if ( dirp - > fsp ! = NULL ) {
/*
* The SMB_VFS_CLOSEDIR above
* closes the underlying fd inside
* dirp - > fsp .
*/
dirp - > fsp - > fh - > fd = - 1 ;
if ( dirp - > fsp - > dptr ! = NULL ) {
SMB_ASSERT ( dirp - > fsp - > dptr - > dir_hnd = = dirp ) ;
dirp - > fsp - > dptr - > dir_hnd = NULL ;
2011-03-18 01:55:15 +03:00
}
2013-04-11 03:24:15 +04:00
dirp - > fsp = NULL ;
2011-03-18 01:55:15 +03:00
}
2008-01-12 19:08:04 +03:00
}
2011-11-09 19:04:09 +04:00
if ( dirp - > conn - > sconn & & ! dirp - > conn - > sconn - > using_smb2 ) {
2011-03-18 02:16:54 +03:00
dirp - > conn - > sconn - > searches . dirhandles_open - - ;
2009-08-06 14:15:51 +04:00
}
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
2016-12-19 22:55:56 +03:00
static struct smb_Dir * OpenDir_internal ( TALLOC_CTX * mem_ctx ,
connection_struct * conn ,
2016-02-27 02:55:14 +03:00
const struct smb_filename * smb_dname ,
2011-02-10 02:05:58 +03:00
const char * mask ,
2015-05-03 07:01:14 +03:00
uint32_t attr )
1996-05-04 11:50:46 +04:00
{
2011-06-07 05:44:43 +04:00
struct smb_Dir * dirp = talloc_zero ( mem_ctx , struct smb_Dir ) ;
2009-08-06 14:15:51 +04:00
struct smbd_server_connection * sconn = conn - > sconn ;
2007-08-24 01:53:00 +04:00
2002-07-15 14:35:28 +04:00
if ( ! dirp ) {
2005-01-29 00:01:58 +03:00
return NULL ;
2002-07-15 14:35:28 +04:00
}
2016-12-20 03:25:26 +03:00
dirp - > dir = SMB_VFS_OPENDIR ( conn , smb_dname , mask , attr ) ;
if ( ! dirp - > dir ) {
DEBUG ( 5 , ( " OpenDir: Can't open %s. %s \n " ,
smb_dname - > base_name ,
strerror ( errno ) ) ) ;
goto fail ;
}
2005-01-29 00:01:58 +03:00
dirp - > conn = conn ;
2007-08-24 01:53:00 +04:00
dirp - > name_cache_size = lp_directory_name_cache_size ( SNUM ( conn ) ) ;
2002-07-15 14:35:28 +04:00
2011-11-09 19:04:09 +04:00
if ( sconn & & ! sconn - > using_smb2 ) {
2011-03-18 02:16:54 +03:00
sconn - > searches . dirhandles_open + + ;
2011-02-10 03:31:06 +03:00
}
talloc_set_destructor ( dirp , smb_Dir_destructor ) ;
return dirp ;
fail :
TALLOC_FREE ( dirp ) ;
return NULL ;
}
2016-12-20 03:35:00 +03:00
/****************************************************************************
Open a directory handle by pathname , ensuring it ' s under the share path .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct smb_Dir * open_dir_safely ( TALLOC_CTX * ctx ,
connection_struct * conn ,
const struct smb_filename * smb_dname ,
const char * wcard ,
uint32_t attr )
{
struct smb_Dir * dir_hnd = NULL ;
struct smb_filename * smb_fname_cwd = NULL ;
char * saved_dir = vfs_GetWd ( ctx , conn ) ;
NTSTATUS status ;
if ( saved_dir = = NULL ) {
return NULL ;
}
if ( vfs_ChDir ( conn , smb_dname - > base_name ) = = - 1 ) {
goto out ;
}
smb_fname_cwd = synthetic_smb_fname ( talloc_tos ( ) ,
" . " ,
NULL ,
NULL ,
smb_dname - > flags ) ;
if ( smb_fname_cwd = = NULL ) {
goto out ;
}
/*
* Now the directory is pinned , use
* REALPATH to ensure we can access it .
*/
status = check_name ( conn , " . " ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
goto out ;
}
dir_hnd = OpenDir_internal ( ctx ,
conn ,
smb_fname_cwd ,
wcard ,
attr ) ;
if ( dir_hnd = = NULL ) {
goto out ;
}
/*
* OpenDir_internal only gets " . " as the dir name .
* Store the real dir name here .
*/
dir_hnd - > dir_smb_fname = cp_smb_filename ( dir_hnd , smb_dname ) ;
if ( ! dir_hnd - > dir_smb_fname ) {
TALLOC_FREE ( dir_hnd ) ;
errno = ENOMEM ;
}
out :
vfs_ChDir ( conn , saved_dir ) ;
TALLOC_FREE ( saved_dir ) ;
return dir_hnd ;
}
2016-12-19 22:55:56 +03:00
struct smb_Dir * OpenDir ( TALLOC_CTX * mem_ctx , connection_struct * conn ,
const struct smb_filename * smb_dname ,
const char * mask ,
uint32_t attr )
{
2016-12-20 03:35:00 +03:00
return open_dir_safely ( mem_ctx ,
2016-12-19 22:55:56 +03:00
conn ,
smb_dname ,
mask ,
attr ) ;
}
2011-02-10 03:31:06 +03:00
/*******************************************************************
Open a directory from an fsp .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct smb_Dir * OpenDir_fsp ( TALLOC_CTX * mem_ctx , connection_struct * conn ,
files_struct * fsp ,
const char * mask ,
2015-05-03 07:01:14 +03:00
uint32_t attr )
2011-02-10 03:31:06 +03:00
{
2011-06-07 05:44:43 +04:00
struct smb_Dir * dirp = talloc_zero ( mem_ctx , struct smb_Dir ) ;
2011-02-10 03:31:06 +03:00
struct smbd_server_connection * sconn = conn - > sconn ;
if ( ! dirp ) {
2016-12-19 23:13:20 +03:00
goto fail ;
}
if ( ! fsp - > is_directory ) {
errno = EBADF ;
goto fail ;
}
if ( fsp - > fh - > fd = = - 1 ) {
errno = EBADF ;
goto fail ;
2011-02-10 03:31:06 +03:00
}
dirp - > conn = conn ;
dirp - > name_cache_size = lp_directory_name_cache_size ( SNUM ( conn ) ) ;
2016-02-27 01:59:51 +03:00
dirp - > dir_smb_fname = cp_smb_filename ( dirp , fsp - > fsp_name ) ;
if ( ! dirp - > dir_smb_fname ) {
2008-08-12 17:19:17 +04:00
errno = ENOMEM ;
2005-01-29 00:01:58 +03:00
goto fail ;
}
2008-01-12 19:08:04 +03:00
2016-12-19 23:13:20 +03:00
dirp - > dir = SMB_VFS_FDOPENDIR ( fsp , mask , attr ) ;
if ( dirp - > dir ! = NULL ) {
dirp - > fsp = fsp ;
} else {
DEBUG ( 10 , ( " OpenDir_fsp: SMB_VFS_FDOPENDIR on %s returned "
" NULL (%s) \n " ,
dirp - > dir_smb_fname - > base_name ,
strerror ( errno ) ) ) ;
if ( errno ! = ENOSYS ) {
2016-12-19 23:15:59 +03:00
goto fail ;
2011-02-10 02:05:58 +03:00
}
}
if ( dirp - > dir = = NULL ) {
2016-12-19 23:35:32 +03:00
/* FDOPENDIR is not supported. Use OPENDIR instead. */
TALLOC_FREE ( dirp ) ;
return open_dir_safely ( mem_ctx ,
conn ,
fsp - > fsp_name ,
2016-02-27 01:59:51 +03:00
mask ,
attr ) ;
2011-02-10 02:05:58 +03:00
}
2016-12-19 23:32:07 +03:00
if ( sconn & & ! sconn - > using_smb2 ) {
sconn - > searches . dirhandles_open + + ;
}
talloc_set_destructor ( dirp , smb_Dir_destructor ) ;
2005-02-01 03:28:20 +03:00
return dirp ;
2002-08-17 19:27:10 +04:00
2005-01-29 00:01:58 +03:00
fail :
2008-01-12 19:08:04 +03:00
TALLOC_FREE ( dirp ) ;
2005-01-29 00:01:58 +03:00
return NULL ;
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
2009-11-16 11:49:23 +03:00
const char * ReadDirName ( struct smb_Dir * dirp , long * poffset ,
SMB_STRUCT_STAT * sbuf , char * * ptalloced )
1996-05-04 11:50:46 +04:00
{
2009-11-16 11:49:23 +03:00
const char * n ;
char * talloced = NULL ;
2005-01-29 00:01:58 +03:00
connection_struct * conn = dirp - > conn ;
1996-05-04 11:50:46 +04:00
2005-06-11 03:13:25 +04:00
/* Cheat to allow . and .. to be the first entries returned. */
2009-01-23 07:18:56 +03:00
if ( ( ( * poffset = = START_OF_DIRECTORY_OFFSET ) | |
( * poffset = = DOT_DOT_DIRECTORY_OFFSET ) ) & & ( dirp - > file_number < 2 ) )
{
2005-06-11 03:13:25 +04:00
if ( dirp - > file_number = = 0 ) {
2009-11-16 11:49:23 +03:00
n = " . " ;
2005-07-22 00:24:21 +04:00
* poffset = dirp - > offset = START_OF_DIRECTORY_OFFSET ;
2005-06-11 03:13:25 +04:00
} else {
2009-11-16 11:49:23 +03:00
n = " .. " ;
2005-07-22 00:24:21 +04:00
* poffset = dirp - > offset = DOT_DOT_DIRECTORY_OFFSET ;
2005-06-11 03:13:25 +04:00
}
dirp - > 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
}
if ( * poffset = = END_OF_DIRECTORY_OFFSET ) {
2005-08-22 01:12:27 +04:00
* poffset = dirp - > offset = END_OF_DIRECTORY_OFFSET ;
return NULL ;
2005-06-11 03:13:25 +04:00
}
2015-02-24 16:46:09 +03:00
/* A real offset, seek to it. */
SeekDir ( dirp , * poffset ) ;
2009-11-16 11:49:23 +03:00
while ( ( n = vfs_readdirname ( conn , dirp - > dir , sbuf , & talloced ) ) ) {
2005-06-11 03:13:25 +04:00
/* Ignore . and .. - we've already returned them. */
if ( * n = = ' . ' ) {
if ( ( n [ 1 ] = = ' \0 ' ) | | ( n [ 1 ] = = ' . ' & & n [ 2 ] = = ' \0 ' ) ) {
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2005-06-11 03:13:25 +04:00
continue ;
}
}
2006-04-08 09:00:04 +04:00
* poffset = dirp - > offset = SMB_VFS_TELLDIR ( conn , dirp - > dir ) ;
2009-11-16 11:49:23 +03:00
* ptalloced = talloced ;
2005-06-11 03:13:25 +04:00
dirp - > file_number + + ;
2006-04-08 09:00:04 +04:00
return n ;
2003-01-03 21:50:13 +03:00
}
2005-08-22 01:12:27 +04:00
* poffset = dirp - > offset = END_OF_DIRECTORY_OFFSET ;
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void RewindDir ( struct smb_Dir * dirp , long * poffset )
{
SMB_VFS_REWINDDIR ( dirp - > conn , dirp - > dir ) ;
dirp - > file_number = 0 ;
2005-07-22 00:24:21 +04:00
dirp - > offset = START_OF_DIRECTORY_OFFSET ;
* poffset = START_OF_DIRECTORY_OFFSET ;
2005-06-15 22:37:34 +04:00
}
2005-01-29 00:01:58 +03:00
/*******************************************************************
Seek a dir .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-05-04 11:50:46 +04:00
2005-02-01 03:28:20 +03:00
void SeekDir ( struct smb_Dir * dirp , long offset )
2005-01-29 00:01:58 +03:00
{
2005-02-01 03:28:20 +03:00
if ( offset ! = dirp - > offset ) {
2005-09-28 00:41:22 +04:00
if ( offset = = START_OF_DIRECTORY_OFFSET ) {
2005-06-15 22:37:34 +04:00
RewindDir ( dirp , & offset ) ;
2007-09-13 01:48:20 +04:00
/*
2005-09-28 00:41:22 +04:00
* Ok we should really set the file number here
* to 1 to enable " .. " to be returned next . Trouble
* is I ' m worried about callers using SeekDir ( dirp , 0 )
* as equivalent to RewindDir ( ) . So leave this alone
* for now .
*/
} else if ( offset = = DOT_DOT_DIRECTORY_OFFSET ) {
RewindDir ( dirp , & offset ) ;
/*
* Set the file number to 2 - we want to get the first
* real file entry ( the one we return after " .. " )
* on the next ReadDir .
*/
dirp - > file_number = 2 ;
2005-08-22 01:12:27 +04:00
} else if ( offset = = END_OF_DIRECTORY_OFFSET ) {
; /* Don't seek in this case. */
2005-06-15 22:37:34 +04:00
} else {
SMB_VFS_SEEKDIR ( dirp - > conn , dirp - > dir , offset ) ;
}
2005-02-01 03:28:20 +03:00
dirp - > offset = offset ;
}
1996-05-04 11:50:46 +04:00
}
/*******************************************************************
1999-12-13 16:27:58 +03:00
Tell a dir position .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2005-02-01 03:28:20 +03:00
long TellDir ( struct smb_Dir * dirp )
1996-05-04 11:50:46 +04:00
{
2005-01-29 00:01:58 +03:00
return ( dirp - > offset ) ;
}
1996-05-04 11:50:46 +04:00
2006-04-08 09:00:04 +04:00
/*******************************************************************
Add an entry into the dcache .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2013-04-16 03:54:20 +04:00
static void DirCacheAdd ( struct smb_Dir * dirp , const char * name , long offset )
2006-04-08 09:00:04 +04:00
{
struct name_cache_entry * e ;
2008-01-08 23:45:21 +03:00
if ( dirp - > name_cache_size = = 0 ) {
2007-08-24 01:53:00 +04:00
return ;
}
2008-01-08 23:45:21 +03:00
if ( dirp - > name_cache = = NULL ) {
2011-06-07 05:58:39 +04:00
dirp - > name_cache = talloc_zero_array (
2008-01-12 19:08:04 +03:00
dirp , struct name_cache_entry , dirp - > name_cache_size ) ;
2008-01-08 23:45:21 +03:00
if ( dirp - > name_cache = = NULL ) {
return ;
}
}
2007-08-24 01:53:00 +04:00
dirp - > name_cache_index = ( dirp - > name_cache_index + 1 ) %
dirp - > name_cache_size ;
2006-04-08 09:00:04 +04:00
e = & dirp - > name_cache [ dirp - > name_cache_index ] ;
2008-01-12 19:08:04 +03:00
TALLOC_FREE ( e - > name ) ;
e - > name = talloc_strdup ( dirp , name ) ;
2006-04-08 09:00:04 +04:00
e - > offset = offset ;
}
2005-01-29 00:01:58 +03:00
/*******************************************************************
Find an entry by name . Leave us at the offset after it .
2005-02-01 21:33:50 +03:00
Don ' t check for veto or invisible files .
2005-01-29 00:01:58 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool SearchDir ( struct smb_Dir * dirp , const char * name , long * poffset )
2005-01-29 00:01:58 +03:00
{
int i ;
2009-11-16 11:49:23 +03:00
const char * entry = NULL ;
char * talloced = NULL ;
2005-01-29 00:01:58 +03:00
connection_struct * conn = dirp - > conn ;
/* Search back in the name cache. */
2007-08-24 01:53:00 +04:00
if ( dirp - > name_cache_size & & dirp - > name_cache ) {
for ( i = dirp - > name_cache_index ; i > = 0 ; i - - ) {
struct name_cache_entry * e = & dirp - > name_cache [ i ] ;
if ( e - > name & & ( conn - > case_sensitive ? ( strcmp ( e - > name , name ) = = 0 ) : strequal ( e - > name , name ) ) ) {
* poffset = e - > offset ;
SeekDir ( dirp , e - > offset ) ;
return True ;
}
2005-01-29 00:01:58 +03:00
}
2007-08-24 01:53:00 +04:00
for ( i = dirp - > name_cache_size - 1 ; i > dirp - > name_cache_index ; i - - ) {
struct name_cache_entry * e = & dirp - > name_cache [ i ] ;
if ( e - > name & & ( conn - > case_sensitive ? ( strcmp ( e - > name , name ) = = 0 ) : strequal ( e - > name , name ) ) ) {
* poffset = e - > offset ;
SeekDir ( dirp , e - > offset ) ;
return True ;
}
2005-01-29 00:01:58 +03:00
}
}
/* Not found in the name cache. Rewind directory and start from scratch. */
SMB_VFS_REWINDDIR ( conn , dirp - > dir ) ;
2005-06-11 03:13:25 +04:00
dirp - > file_number = 0 ;
2005-07-22 00:24:21 +04:00
* poffset = START_OF_DIRECTORY_OFFSET ;
2009-11-16 11:49:23 +03:00
while ( ( entry = ReadDirName ( dirp , poffset , NULL , & talloced ) ) ) {
2005-02-01 21:33:50 +03:00
if ( conn - > case_sensitive ? ( strcmp ( entry , name ) = = 0 ) : strequal ( entry , name ) ) {
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2005-01-29 00:01:58 +03:00
return True ;
}
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2005-01-29 00:01:58 +03:00
}
return False ;
1996-05-04 11:50:46 +04:00
}
2007-02-09 05:03:39 +03:00
2014-09-25 03:30:33 +04:00
struct files_below_forall_state {
char * dirpath ;
size_t dirpath_len ;
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 ;
size_t len ;
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
*/
return 0 ;
}
if ( fullpath [ state - > dirpath_len ] ! = ' / ' ) {
/*
* Filter file that don ' t have a path separator at the end of
* dirpath ' s length
*/
return 0 ;
}
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
*/
return 0 ;
}
2015-11-24 01:00:56 +03:00
return state - > fn ( fid , data , state - > private_data ) ;
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 ;
long dirpos = 0 ;
2009-11-16 11:49:23 +03:00
const char * dname = NULL ;
2012-11-15 02:40:51 +04:00
const char * dirname = fsp - > fsp_name - > base_name ;
2009-11-16 11:49:23 +03:00
char * talloced = NULL ;
2009-01-23 07:18:56 +03:00
SMB_STRUCT_STAT st ;
2012-11-15 02:40:51 +04:00
struct connection_struct * conn = fsp - > conn ;
struct smb_Dir * dir_hnd = OpenDir_fsp ( talloc_tos ( ) ,
conn ,
fsp ,
NULL ,
0 ) ;
2007-02-09 05:03:39 +03:00
if ( ! dir_hnd ) {
return map_nt_error_from_unix ( errno ) ;
}
2009-11-16 11:49:23 +03:00
while ( ( dname = ReadDirName ( dir_hnd , & dirpos , & st , & talloced ) ) ) {
2007-02-09 05:03:39 +03:00
/* Quick check for "." and ".." */
if ( dname [ 0 ] = = ' . ' ) {
if ( ! dname [ 1 ] | | ( dname [ 1 ] = = ' . ' & & ! dname [ 2 ] ) ) {
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2007-02-09 05:03:39 +03:00
continue ;
}
}
if ( ! is_visible_file ( conn , dirname , dname , & st , True ) ) {
2009-11-16 11:49:23 +03:00
TALLOC_FREE ( talloced ) ;
2007-02-09 05:03:39 +03:00
continue ;
}
2012-11-15 02:40:51 +04:00
DEBUG ( 10 , ( " got name %s - can't delete \n " ,
2009-01-23 07:18:56 +03:00
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
}