1996-05-04 11:50:46 +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
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
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
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 .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
/*
This module implements directory related functions for Samba .
*/
2005-04-06 20:28:04 +04:00
extern struct current_user current_user ;
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. */
# define NAME_CACHE_SIZE 100
struct name_cache_entry {
char * name ;
long offset ;
} ;
struct smb_Dir {
connection_struct * conn ;
2005-08-22 22:03:08 +04:00
SMB_STRUCT_DIR * dir ;
2005-02-01 03:28:20 +03:00
long offset ;
char * dir_path ;
struct name_cache_entry * name_cache ;
unsigned int name_cache_index ;
2005-06-11 03:13:25 +04:00
unsigned int file_number ;
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 ;
uint16 spid ;
2005-02-01 03:28:20 +03:00
struct connection_struct * conn ;
struct smb_Dir * dir_hnd ;
1998-08-14 21:38:29 +04:00
BOOL expect_close ;
2005-02-01 03:28:20 +03:00
char * wcard ;
2005-06-25 07:03:44 +04:00
uint32 attr ;
1998-08-14 21:38:29 +04:00
char * path ;
2005-02-01 03:28:20 +03:00
BOOL has_wild ; /* Set to true if the wcard entry has MS wildcard characters in it. */
} ;
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
static struct bitmap * dptr_bmap ;
2005-02-01 03:28:20 +03:00
static struct dptr_struct * dirptrs ;
2005-02-03 05:02:54 +03:00
static int dirhandles_open = 0 ;
1996-05-04 11:50:46 +04:00
1999-12-13 16:27:58 +03:00
# define INVALID_DPTR_KEY (-3)
2005-05-01 14:00:14 +04:00
/****************************************************************************
Make a dir struct .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-06-25 07:03:44 +04:00
void make_dir_struct ( char * buf , const char * mask , const char * fname , SMB_OFF_T size , uint32 mode , time_t date , BOOL uc )
2005-05-01 14:00:14 +04:00
{
char * p ;
pstring mask2 ;
pstrcpy ( mask2 , mask ) ;
if ( ( mode & aDIR ) ! = 0 )
size = 0 ;
memset ( buf + 1 , ' ' , 11 ) ;
if ( ( p = strchr_m ( mask2 , ' . ' ) ) ! = NULL ) {
* p = 0 ;
push_ascii ( buf + 1 , mask2 , 8 , 0 ) ;
push_ascii ( buf + 9 , p + 1 , 3 , 0 ) ;
* p = ' . ' ;
} else
push_ascii ( buf + 1 , mask2 , 11 , 0 ) ;
memset ( buf + 21 , ' \0 ' , DIR_STRUCT_SIZE - 21 ) ;
SCVAL ( buf , 21 , mode ) ;
2005-11-05 07:21:55 +03:00
srv_put_dos_date ( buf , 22 , date ) ;
2005-05-01 14:00:14 +04:00
SSVAL ( buf , 26 , size & 0xFFFF ) ;
SSVAL ( buf , 28 , ( size > > 16 ) & 0xFFFF ) ;
/* We only uppercase if FLAGS2_LONG_PATH_COMPONENTS is zero in the input buf.
Strange , but verified on W2K3 . Needed for OS / 2. JRA . */
push_ascii ( buf + 30 , fname , 12 , uc ? STR_UPPER : 0 ) ;
DEBUG ( 8 , ( " put name [%s] from [%s] into dir struct \n " , buf + 30 , fname ) ) ;
}
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
1996-05-04 11:50:46 +04:00
void init_dptrs ( void )
{
2003-01-03 21:50:13 +03:00
static BOOL dptrs_init = False ;
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
if ( dptrs_init )
return ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
dptr_bmap = bitmap_allocate ( MAX_DIRECTORY_HANDLES ) ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
if ( ! dptr_bmap )
exit_server ( " out of memory in init_dptrs " ) ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
dptrs_init = 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 ) ) ;
2005-02-01 03:28:20 +03:00
CloseDir ( dptr - > dir_hnd ) ;
dptr - > dir_hnd = NULL ;
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
1996-05-04 11:50:46 +04:00
static void dptr_idleoldest ( void )
{
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 .
*/
for ( dptr = dirptrs ; dptr & & dptr - > next ; dptr = dptr - > next )
;
if ( ! dptr ) {
DEBUG ( 0 , ( " No dptrs available to idle ? \n " ) ) ;
return ;
}
/*
* Idle the oldest pointer .
*/
for ( ; dptr ; dptr = dptr - > prev ) {
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
2005-02-01 03:28:20 +03:00
static struct dptr_struct * dptr_get ( 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
for ( dptr = dirptrs ; dptr ; dptr = dptr - > next ) {
if ( dptr - > dnum = = key ) {
2005-02-01 03:28:20 +03:00
if ( ! forclose & & ! dptr - > dir_hnd ) {
2005-02-03 05:02:54 +03:00
if ( dirhandles_open > = MAX_OPEN_DIRECTORIES )
2003-01-03 21:50:13 +03:00
dptr_idleoldest ( ) ;
2005-02-01 03:28:20 +03:00
DEBUG ( 4 , ( " dptr_get: Reopening dptr key %d \n " , key ) ) ;
2005-06-25 07:03:44 +04:00
if ( ! ( dptr - > dir_hnd = OpenDir ( dptr - > conn , dptr - > path , dptr - > wcard , dptr - > attr ) ) ) {
2005-02-01 03:28:20 +03:00
DEBUG ( 4 , ( " dptr_get: Failed to open %s (%s) \n " , dptr - > path ,
strerror ( errno ) ) ) ;
return False ;
}
2003-01-03 21:50:13 +03:00
}
DLIST_PROMOTE ( dirptrs , dptr ) ;
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-05-04 11:50:46 +04:00
char * dptr_path ( int key )
{
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr = dptr_get ( key , False ) ;
2003-01-03 21:50:13 +03:00
if ( dptr )
return ( dptr - > path ) ;
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
1996-05-04 11:50:46 +04:00
char * dptr_wcard ( int key )
{
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr = dptr_get ( 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
2005-02-01 03:28:20 +03:00
uint16 dptr_attr ( int key )
1996-05-04 11:50:46 +04:00
{
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr = dptr_get ( key , False ) ;
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
{
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
2003-01-03 21:50:13 +03:00
DLIST_REMOVE ( dirptrs , dptr ) ;
1999-12-13 16:27:58 +03: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
2003-01-03 21:50:13 +03:00
if ( bitmap_query ( dptr_bmap , dptr - > dnum - 1 ) ! = True ) {
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
2003-01-03 21:50:13 +03:00
bitmap_clear ( dptr_bmap , dptr - > dnum - 1 ) ;
1999-12-13 16:27:58 +03:00
2005-02-01 03:28:20 +03:00
if ( dptr - > dir_hnd ) {
CloseDir ( dptr - > dir_hnd ) ;
2003-01-03 21:50:13 +03:00
}
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
/* Lanman 2 specific code */
SAFE_FREE ( dptr - > wcard ) ;
string_set ( & dptr - > path , " " ) ;
SAFE_FREE ( dptr ) ;
1999-12-13 16:27:58 +03:00
}
/****************************************************************************
Close a dptr given a key .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void dptr_close ( int * key )
{
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 ;
2003-01-03 21:50:13 +03:00
for ( dptr = dirptrs ; dptr ; dptr = next ) {
next = dptr - > next ;
dptr_close_internal ( dptr ) ;
}
* key = INVALID_DPTR_KEY ;
return ;
}
1996-05-05 15:23:23 +04:00
2003-01-03 21:50:13 +03:00
dptr = dptr_get ( * 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 ;
2003-01-03 21:50:13 +03:00
for ( dptr = dirptrs ; dptr ; dptr = next ) {
next = dptr - > next ;
if ( dptr - > conn = = conn )
dptr_close_internal ( dptr ) ;
}
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 ;
2003-01-03 21:50:13 +03:00
for ( dptr = dirptrs ; dptr ; dptr = dptr - > next ) {
2005-02-01 03:28:20 +03:00
if ( dptr - > conn = = conn & & dptr - > dir_hnd )
2003-01-03 21:50:13 +03:00
dptr_idle ( dptr ) ;
}
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
void dptr_closepath ( char * path , uint16 spid )
1996-05-04 11:50:46 +04:00
{
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr , * next ;
2003-01-03 21:50:13 +03:00
for ( dptr = dirptrs ; dptr ; dptr = next ) {
next = dptr - > next ;
if ( spid = = dptr - > spid & & strequal ( dptr - > path , path ) )
dptr_close_internal ( dptr ) ;
}
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void dptr_close_oldest ( BOOL old )
{
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 .
*/
for ( dptr = dirptrs ; dptr & & dptr - > next ; dptr = dptr - > next )
;
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 .
*/
for ( ; dptr ; dptr = dptr - > prev ) {
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
/****************************************************************************
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
2005-06-25 07:03:44 +04:00
int dptr_create ( connection_struct * conn , pstring path , BOOL old_handle , BOOL expect_close , uint16 spid ,
2005-10-31 23:11:58 +03:00
const char * wcard , BOOL wcard_has_wild , uint32 attr )
1996-05-04 11:50:46 +04:00
{
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr = NULL ;
struct smb_Dir * dir_hnd ;
const char * dir2 ;
DEBUG ( 5 , ( " dptr_create dir=%s \n " , path ) ) ;
1996-05-04 11:50:46 +04:00
2005-08-13 03:45:16 +04:00
if ( ! wcard ) {
return - 1 ;
}
2005-02-01 03:28:20 +03:00
if ( ! check_name ( path , conn ) )
2003-01-03 21:50:13 +03:00
return ( - 2 ) ; /* Code to say use a unix error return code. */
1996-05-04 11:50:46 +04:00
2005-02-01 03:28:20 +03:00
/* use a const pointer from here on */
dir2 = path ;
if ( ! * dir2 )
dir2 = " . " ;
2005-06-25 07:03:44 +04:00
dir_hnd = OpenDir ( conn , dir2 , wcard , attr ) ;
2005-02-01 03:28:20 +03:00
if ( ! dir_hnd ) {
return ( - 2 ) ;
}
string_set ( & conn - > dirpath , dir2 ) ;
2005-02-03 05:02:54 +03:00
if ( dirhandles_open > = MAX_OPEN_DIRECTORIES )
2003-01-03 21:50:13 +03:00
dptr_idleoldest ( ) ;
1999-12-13 16:27:58 +03:00
2005-02-01 03:28:20 +03:00
dptr = SMB_MALLOC_P ( struct dptr_struct ) ;
2003-01-03 21:50:13 +03:00
if ( ! dptr ) {
DEBUG ( 0 , ( " malloc fail in dptr_create. \n " ) ) ;
2005-02-01 03:28:20 +03:00
CloseDir ( dir_hnd ) ;
2003-01-03 21:50:13 +03:00
return - 1 ;
}
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
ZERO_STRUCTP ( dptr ) ;
1999-12-13 16:27:58 +03:00
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
2003-01-03 21:50:13 +03:00
dptr - > dnum = bitmap_find ( 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
2003-01-03 21:50:13 +03:00
dptr_close_oldest ( True ) ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
/* Now try again... */
dptr - > dnum = bitmap_find ( dptr_bmap , 0 ) ;
if ( dptr - > dnum = = - 1 | | dptr - > dnum > 254 ) {
DEBUG ( 0 , ( " dptr_create: returned %d: Error - all old dirptrs in use ? \n " , dptr - > dnum ) ) ;
SAFE_FREE ( dptr ) ;
2005-02-01 03:28:20 +03:00
CloseDir ( dir_hnd ) ;
2003-01-03 21:50:13 +03:00
return - 1 ;
}
}
} 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
2003-01-03 21:50:13 +03:00
dptr - > dnum = bitmap_find ( 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
2003-01-03 21:50:13 +03:00
dptr_close_oldest ( False ) ;
1999-12-13 16:27:58 +03:00
2003-01-03 21:50:13 +03:00
/* Now try again... */
dptr - > dnum = bitmap_find ( 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 ) ) ;
SAFE_FREE ( dptr ) ;
2005-02-01 03:28:20 +03:00
CloseDir ( dir_hnd ) ;
2003-01-03 21:50:13 +03:00
return - 1 ;
}
}
}
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
bitmap_set ( 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
2005-02-01 03:28:20 +03:00
string_set ( & dptr - > path , dir2 ) ;
2003-01-03 21:50:13 +03:00
dptr - > conn = conn ;
2005-02-01 03:28:20 +03:00
dptr - > dir_hnd = dir_hnd ;
2003-01-03 21:50:13 +03:00
dptr - > spid = spid ;
dptr - > expect_close = expect_close ;
2005-08-13 03:45:16 +04:00
dptr - > wcard = SMB_STRDUP ( wcard ) ;
if ( ! dptr - > wcard ) {
bitmap_clear ( dptr_bmap , dptr - > dnum - 1 ) ;
SAFE_FREE ( dptr ) ;
CloseDir ( dir_hnd ) ;
return - 1 ;
2005-06-25 07:03:44 +04:00
}
2005-08-13 03:45:16 +04:00
if ( lp_posix_pathnames ( ) | | ( wcard [ 0 ] = = ' . ' & & wcard [ 1 ] = = 0 ) ) {
2005-06-25 07:03:44 +04:00
dptr - > has_wild = True ;
} else {
2005-10-31 23:11:58 +03:00
dptr - > has_wild = wcard_has_wild ;
2005-06-25 07:03:44 +04:00
}
1999-12-13 16:27:58 +03:00
2005-08-13 03:45:16 +04:00
dptr - > attr = attr ;
2003-01-03 21:50:13 +03:00
DLIST_ADD ( dirptrs , dptr ) ;
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
DEBUG ( 3 , ( " creating new dirptr %d for path %s, expect_close = %d \n " ,
dptr - > dnum , path , expect_close ) ) ;
1996-05-04 11:50:46 +04:00
2005-02-01 03:28:20 +03:00
conn - > dirptr = dptr ;
2003-01-03 21:50:13 +03:00
return ( dptr - > dnum ) ;
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int dptr_CloseDir ( struct dptr_struct * dptr )
{
return CloseDir ( dptr - > dir_hnd ) ;
}
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 ) ;
}
2005-02-01 21:33:50 +03:00
/****************************************************************************
Return the next visible file name , skipping veto ' d and invisible files .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static const char * dptr_normal_ReadDirName ( struct dptr_struct * dptr , long * poffset , SMB_STRUCT_STAT * pst )
2005-02-01 03:28:20 +03:00
{
2005-02-01 21:33:50 +03:00
/* Normal search for the next file. */
const char * name ;
while ( ( name = ReadDirName ( dptr - > dir_hnd , poffset ) ) ! = NULL ) {
if ( is_visible_file ( dptr - > conn , dptr - > path , name , pst , True ) ) {
return name ;
}
}
return NULL ;
}
/****************************************************************************
Return the next visible file name , skipping veto ' d and invisible files .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
const char * dptr_ReadDirName ( struct dptr_struct * dptr , long * poffset , SMB_STRUCT_STAT * pst )
{
pstring pathreal ;
2005-06-03 09:35:04 +04:00
SET_STAT_INVALID ( * pst ) ;
2005-03-03 05:04:36 +03:00
2005-02-01 21:33:50 +03:00
if ( dptr - > has_wild ) {
return dptr_normal_ReadDirName ( dptr , poffset , pst ) ;
}
2005-03-03 05:04:36 +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 ;
}
2005-02-01 21:33:50 +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 has_wild to true to
prevent us from doing this on every call . */
/* First check if it should be visible. */
if ( ! is_visible_file ( dptr - > conn , dptr - > path , dptr - > wcard , pst , True ) ) {
dptr - > has_wild = True ;
return dptr_normal_ReadDirName ( dptr , poffset , pst ) ;
}
if ( VALID_STAT ( * pst ) ) {
2005-03-03 05:04:36 +03:00
/* We need to set the underlying dir_hdn offset to -1 also as
this function is usually called with the output from TellDir . */
2005-07-22 00:24:21 +04:00
dptr - > dir_hnd - > offset = * poffset = END_OF_DIRECTORY_OFFSET ;
2005-02-01 21:33:50 +03:00
return dptr - > wcard ;
}
pstrcpy ( pathreal , dptr - > path ) ;
pstrcat ( pathreal , " / " ) ;
pstrcat ( pathreal , dptr - > wcard ) ;
if ( SMB_VFS_STAT ( dptr - > conn , pathreal , pst ) = = 0 ) {
2005-03-03 05:04:36 +03:00
/* We need to set the underlying dir_hdn offset to -1 also as
this function is usually called with the output from TellDir . */
2005-07-22 00:24:21 +04:00
dptr - > dir_hnd - > offset = * poffset = END_OF_DIRECTORY_OFFSET ;
2005-02-01 21:33:50 +03:00
return dptr - > wcard ;
} 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 ) {
2005-03-03 05:04:36 +03:00
/* We need to set the underlying dir_hdn offset to -1 also as
this function is usually called with the output from TellDir . */
2005-07-22 00:24:21 +04:00
dptr - > dir_hnd - > offset = * poffset = END_OF_DIRECTORY_OFFSET ;
2005-02-01 21:33:50 +03:00
return dptr - > wcard ;
}
}
/* In case sensitive mode we don't search - we know if it doesn't exist
with a stat we will fail . */
if ( dptr - > conn - > case_sensitive ) {
2005-03-03 05:04:36 +03:00
/* We need to set the underlying dir_hdn offset to -1 also as
this function is usually called with the output from TellDir . */
2005-07-22 00:24:21 +04:00
dptr - > dir_hnd - > offset = * poffset = END_OF_DIRECTORY_OFFSET ;
2005-02-01 21:33:50 +03:00
return NULL ;
} else {
2005-04-01 23:57:22 +04:00
dptr - > has_wild = True ;
2005-02-01 21:33:50 +03:00
return dptr_normal_ReadDirName ( dptr , poffset , pst ) ;
}
}
/****************************************************************************
Search for a file by name , skipping veto ' ed and not visible files .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL dptr_SearchDir ( struct dptr_struct * dptr , const char * name , long * poffset , SMB_STRUCT_STAT * pst )
{
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
}
2006-04-08 09:00:04 +04:00
/****************************************************************************
Add the name we ' re returning into the underlying cache .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void dptr_DirCacheAdd ( struct dptr_struct * dptr , const char * name , long offset )
{
DirCacheAdd ( dptr - > dir_hnd , name , offset ) ;
}
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
1997-07-24 21:25:11 +04:00
BOOL dptr_fill ( 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 ;
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr = dptr_get ( key , False ) ;
2003-01-03 21:50:13 +03:00
uint32 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 ) ;
}
2005-05-01 13:30:18 +04:00
offset = ( uint32 ) 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 ,
2005-02-01 03:28:20 +03:00
( long ) dptr - > dir_hnd , ( int ) offset ) ) ;
2003-01-03 21:50:13 +03:00
buf [ 0 ] = key ;
2005-07-20 22:21:38 +04:00
SIVAL ( buf , 1 , offset ) ;
2003-01-03 21:50:13 +03:00
return ( True ) ;
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
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr_fetch ( 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 ;
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr = dptr_get ( key , False ) ;
2003-01-03 21:50:13 +03:00
uint32 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 ;
2005-05-01 13:30:18 +04:00
offset = IVAL ( buf , 1 ) ;
if ( offset = = ( uint32 ) - 1 ) {
2005-07-22 00:24:21 +04:00
seekoff = END_OF_DIRECTORY_OFFSET ;
2005-05-01 13:30:18 +04:00
} else {
2005-07-20 22:21:38 +04:00
seekoff = ( long ) 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 " ,
2005-05-01 13:30:18 +04:00
key , dptr_path ( key ) , ( 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
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr_fetch_lanman2 ( int dptr_num )
1996-05-04 11:50:46 +04:00
{
2005-02-01 03:28:20 +03:00
struct dptr_struct * dptr = dptr_get ( 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 ) ;
}
DEBUG ( 3 , ( " fetching dirptr %d for path %s \n " , dptr_num , dptr_path ( dptr_num ) ) ) ;
2005-02-01 03:28:20 +03:00
return ( dptr ) ;
1996-05-04 11:50:46 +04:00
}
1996-06-05 19:16:09 +04:00
/****************************************************************************
2006-04-24 14:45:06 +04:00
Check that a file matches a particular file type .
1996-06-05 19:16:09 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2005-06-25 07:03:44 +04:00
BOOL dir_check_ftype ( connection_struct * conn , uint32 mode , uint32 dirtype )
1996-06-05 19:16:09 +04:00
{
2005-06-25 07:03:44 +04:00
uint32 mask ;
2002-09-25 19:19:00 +04:00
/* Check the "may have" search bits. */
if ( ( ( mode & ~ dirtype ) & ( aHIDDEN | aSYSTEM | aDIR ) ) ! = 0 )
return False ;
/* Check the "must have" bits, which are the may have bits shifted eight */
/* If must have bit is set, the file/dir can not be returned in search unless the matching
file attribute is set */
mask = ( ( dirtype > > 8 ) & ( aDIR | aARCH | aRONLY | aHIDDEN | aSYSTEM ) ) ; /* & 0x37 */
if ( mask ) {
if ( ( mask & ( mode & ( aDIR | aARCH | aRONLY | aHIDDEN | aSYSTEM ) ) ) = = mask ) /* check if matching attribute present */
return True ;
else
return False ;
}
return True ;
1996-06-05 19:16:09 +04:00
}
2003-03-18 01:56:13 +03:00
static BOOL mangle_mask_match ( connection_struct * conn , fstring filename , char * mask )
2002-07-15 14:35:28 +04:00
{
mangle_map ( filename , True , False , SNUM ( conn ) ) ;
2005-03-24 22:33:02 +03:00
return mask_match_search ( filename , mask , False ) ;
2002-07-15 14:35:28 +04:00
}
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
2005-06-25 07:03:44 +04:00
BOOL get_dir_entry ( connection_struct * conn , char * mask , uint32 dirtype , pstring fname ,
SMB_OFF_T * size , uint32 * mode , time_t * date , BOOL check_descend )
1996-05-04 11:50:46 +04:00
{
2003-03-18 01:56:13 +03:00
const char * dname ;
2003-01-03 21:50:13 +03:00
BOOL found = False ;
SMB_STRUCT_STAT sbuf ;
pstring path ;
pstring pathreal ;
pstring filename ;
BOOL needslash ;
* path = * pathreal = * filename = 0 ;
needslash = ( conn - > dirpath [ strlen ( conn - > dirpath ) - 1 ] ! = ' / ' ) ;
1997-05-20 04:32:51 +04:00
2003-01-03 21:50:13 +03:00
if ( ! conn - > dirptr )
return ( False ) ;
2001-02-08 23:47:09 +03:00
2003-01-03 21:50:13 +03:00
while ( ! found ) {
2005-02-01 21:33:50 +03:00
long curoff = dptr_TellDir ( conn - > dirptr ) ;
dname = dptr_ReadDirName ( conn - > dirptr , & curoff , & sbuf ) ;
1996-05-04 11:50:46 +04:00
2005-01-29 00:01:58 +03:00
DEBUG ( 6 , ( " readdir on dirptr 0x%lx now at offset %ld \n " ,
2005-02-01 03:28:20 +03:00
( long ) conn - > dirptr , TellDir ( conn - > dirptr - > dir_hnd ) ) ) ;
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
if ( dname = = NULL )
return ( False ) ;
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
pstrcpy ( filename , dname ) ;
/* notice the special *.* handling. This appears to be the only difference
between the wildcard handling in this routine and in the trans2 routines .
see masktest for a demo
*/
if ( ( strcmp ( mask , " *.* " ) = = 0 ) | |
2005-03-24 22:33:02 +03:00
mask_match_search ( filename , mask , False ) | |
2003-04-14 07:48:26 +04:00
mangle_mask_match ( conn , filename , mask ) ) {
2003-01-03 21:50:13 +03:00
2005-05-06 12:07:39 +04:00
if ( ! mangle_is_8_3 ( filename , False , SNUM ( conn ) ) )
2003-01-03 21:50:13 +03:00
mangle_map ( filename , True , False , SNUM ( conn ) ) ;
pstrcpy ( fname , filename ) ;
* path = 0 ;
pstrcpy ( path , conn - > dirpath ) ;
if ( needslash )
pstrcat ( path , " / " ) ;
pstrcpy ( pathreal , path ) ;
pstrcat ( path , fname ) ;
pstrcat ( pathreal , dname ) ;
2005-02-01 21:33:50 +03:00
if ( ! VALID_STAT ( sbuf ) & & ( SMB_VFS_STAT ( conn , pathreal , & sbuf ) ) ! = 0 ) {
2003-01-03 21:50:13 +03:00
DEBUG ( 5 , ( " Couldn't stat 1 [%s]. Error = %s \n " , path , strerror ( errno ) ) ) ;
continue ;
}
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
* mode = dos_mode ( conn , pathreal , & sbuf ) ;
1999-12-13 16:27:58 +03:00
2005-02-01 21:33:50 +03:00
if ( ! dir_check_ftype ( conn , * mode , dirtype ) ) {
2005-11-11 00:34:25 +03:00
DEBUG ( 5 , ( " [%s] attribs 0x%x didn't match 0x%x \n " , filename , ( unsigned int ) * mode , ( unsigned int ) dirtype ) ) ;
2003-01-03 21:50:13 +03:00
continue ;
}
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
* size = sbuf . st_size ;
* date = sbuf . st_mtime ;
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
DEBUG ( 3 , ( " get_dir_entry mask=[%s] found %s fname=%s \n " , mask , pathreal , fname ) ) ;
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
found = True ;
2006-04-08 09:00:04 +04:00
DirCacheAdd ( conn - > dirptr - > dir_hnd , dname , curoff ) ;
2003-01-03 21:50:13 +03:00
}
}
1996-05-04 11:50:46 +04:00
2003-01-03 21:50:13 +03:00
return ( found ) ;
}
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
2002-09-25 19:19:00 +04:00
static BOOL user_can_read_file ( connection_struct * conn , char * name , SMB_STRUCT_STAT * pst )
2001-04-16 19:16:31 +04:00
{
2001-12-17 22:16:22 +03:00
SEC_DESC * psd = NULL ;
size_t sd_size ;
files_struct * fsp ;
NTSTATUS status ;
uint32 access_granted ;
2002-07-15 14:35:28 +04:00
/*
* If user is a member of the Admin group
* we never hide files from them .
*/
2005-07-08 08:51:27 +04:00
if ( conn - > admin_user ) {
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
/* If we can't stat it does not show it */
2005-07-08 08:51:27 +04:00
if ( ! VALID_STAT ( * pst ) & & ( SMB_VFS_STAT ( conn , name , pst ) ! = 0 ) ) {
2006-06-27 03:36:03 +04:00
DEBUG ( 10 , ( " user_can_read_file: SMB_VFS_STAT failed for file %s with error %s \n " ,
name , strerror ( errno ) ) ) ;
2001-12-17 22:16:22 +03:00
return False ;
2005-07-08 08:51:27 +04:00
}
2001-12-17 22:16:22 +03:00
/* Pseudo-open the file (note - no fd's created). */
2005-07-08 08:51:27 +04:00
if ( S_ISDIR ( pst - > st_mode ) ) {
fsp = open_directory ( conn , name , pst ,
READ_CONTROL_ACCESS ,
FILE_SHARE_READ | FILE_SHARE_WRITE ,
FILE_OPEN ,
0 , /* no create options. */
NULL ) ;
} else {
2003-01-03 21:50:13 +03:00
fsp = open_file_stat ( conn , name , pst ) ;
2005-07-08 08:51:27 +04:00
}
2002-03-20 03:46:53 +03:00
2005-07-08 08:51:27 +04:00
if ( ! fsp ) {
2001-12-17 22:16:22 +03:00
return False ;
2005-07-08 08:51:27 +04:00
}
2001-12-17 22:16:22 +03:00
/* Get NT ACL -allocated in main loop talloc context. No free needed here. */
2005-07-08 08:51:27 +04:00
sd_size = SMB_VFS_FGET_NT_ACL ( fsp , fsp - > fh - > fd ,
2003-05-30 03:49:31 +04:00
( OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION ) , & psd ) ;
2006-02-02 23:44:50 +03:00
close_file ( fsp , NORMAL_CLOSE ) ;
2001-12-17 22:16:22 +03:00
/* No access if SD get failed. */
2005-07-08 08:51:27 +04:00
if ( ! sd_size ) {
2001-12-17 22:16:22 +03:00
return False ;
2005-07-08 08:51:27 +04:00
}
2001-12-17 22:16:22 +03:00
return se_access_check ( psd , current_user . nt_user_token , FILE_READ_DATA ,
& access_granted , & status ) ;
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
static BOOL user_can_write_file ( connection_struct * conn , char * name , SMB_STRUCT_STAT * pst )
2002-08-17 19:27:10 +04:00
{
SEC_DESC * psd = NULL ;
size_t sd_size ;
files_struct * fsp ;
2005-07-08 08:51:27 +04:00
int info ;
2002-08-17 19:27:10 +04:00
NTSTATUS status ;
uint32 access_granted ;
/*
* If user is a member of the Admin group
* we never hide files from them .
*/
2005-07-08 08:51:27 +04:00
if ( conn - > admin_user ) {
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
/* If we can't stat it does not show it */
2005-07-08 08:51:27 +04:00
if ( ! VALID_STAT ( * pst ) & & ( SMB_VFS_STAT ( conn , name , pst ) ! = 0 ) ) {
2002-08-17 19:27:10 +04:00
return False ;
2005-07-08 08:51:27 +04:00
}
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
2005-07-08 08:51:27 +04:00
if ( S_ISDIR ( pst - > st_mode ) ) {
2002-08-17 19:27:10 +04:00
return True ;
2005-07-08 08:51:27 +04:00
} else {
fsp = open_file_ntcreate ( conn , name , pst ,
FILE_WRITE_ATTRIBUTES ,
FILE_SHARE_READ | FILE_SHARE_WRITE ,
FILE_OPEN ,
0 ,
FILE_ATTRIBUTE_NORMAL ,
INTERNAL_OPEN_ONLY ,
& info ) ;
}
2002-08-17 19:27:10 +04:00
2005-07-08 08:51:27 +04:00
if ( ! fsp ) {
2002-08-17 19:27:10 +04:00
return False ;
2005-07-08 08:51:27 +04:00
}
2002-08-17 19:27:10 +04:00
/* Get NT ACL -allocated in main loop talloc context. No free needed here. */
2005-07-08 08:51:27 +04:00
sd_size = SMB_VFS_FGET_NT_ACL ( fsp , fsp - > fh - > fd ,
2003-05-30 03:49:31 +04:00
( OWNER_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | DACL_SECURITY_INFORMATION ) , & psd ) ;
2006-02-02 23:44:50 +03:00
close_file ( fsp , NORMAL_CLOSE ) ;
2002-08-17 19:27:10 +04:00
/* No access if SD get failed. */
if ( ! sd_size )
return False ;
return se_access_check ( psd , current_user . nt_user_token , FILE_WRITE_DATA ,
& access_granted , & status ) ;
}
2002-09-25 19:19:00 +04:00
/*******************************************************************
Is a file a " special " type ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL file_is_special ( connection_struct * conn , char * name , SMB_STRUCT_STAT * pst )
{
/*
* If user is a member of the Admin group
* we never hide files from them .
*/
if ( conn - > admin_user )
2003-12-23 10:33:42 +03:00
return False ;
2002-09-25 19:19:00 +04:00
/* If we can't stat it does not show it */
2003-05-14 14:59:01 +04:00
if ( ! VALID_STAT ( * pst ) & & ( SMB_VFS_STAT ( conn , name , pst ) ! = 0 ) )
2002-09-25 19:19:00 +04:00
return True ;
if ( S_ISREG ( pst - > st_mode ) | | S_ISDIR ( pst - > st_mode ) | | S_ISLNK ( pst - > st_mode ) )
return False ;
return True ;
}
2005-02-01 21:33:50 +03:00
/*******************************************************************
Should the file be seen by the client ?
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL is_visible_file ( connection_struct * conn , const char * dir_path , const char * name , SMB_STRUCT_STAT * pst , BOOL use_veto )
{
BOOL hide_unreadable = lp_hideunreadable ( SNUM ( conn ) ) ;
BOOL hide_unwriteable = lp_hideunwriteable_files ( SNUM ( conn ) ) ;
BOOL hide_special = lp_hide_special_files ( SNUM ( conn ) ) ;
2005-06-03 09:35:04 +04:00
SET_STAT_INVALID ( * pst ) ;
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 */
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 ) {
char * entry = NULL ;
if ( asprintf ( & entry , " %s/%s " , dir_path , name ) = = - 1 ) {
return False ;
}
/* Honour _hide unreadable_ option */
if ( hide_unreadable & & ! user_can_read_file ( conn , entry , pst ) ) {
2006-06-27 03:36:03 +04:00
DEBUG ( 10 , ( " is_visible_file: file %s is unreadable. \n " , entry ) ) ;
2005-02-01 21:33:50 +03:00
SAFE_FREE ( entry ) ;
return False ;
}
/* Honour _hide unwriteable_ option */
if ( hide_unwriteable & & ! user_can_write_file ( conn , entry , pst ) ) {
2006-06-27 03:36:03 +04:00
DEBUG ( 10 , ( " is_visible_file: file %s is unwritable. \n " , entry ) ) ;
2005-02-01 21:33:50 +03:00
SAFE_FREE ( entry ) ;
return False ;
}
/* Honour _hide_special_ option */
2005-04-26 03:15:48 +04:00
if ( hide_special & & file_is_special ( conn , entry , pst ) ) {
2006-06-27 03:36:03 +04:00
DEBUG ( 10 , ( " is_visible_file: file %s is special. \n " , entry ) ) ;
2005-02-01 21:33:50 +03:00
SAFE_FREE ( entry ) ;
return False ;
}
SAFE_FREE ( entry ) ;
}
return True ;
}
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
2005-06-25 07:03:44 +04:00
struct smb_Dir * OpenDir ( connection_struct * conn , const char * name , const char * mask , uint32 attr )
1996-05-04 11:50:46 +04:00
{
2005-02-01 03:28:20 +03:00
struct smb_Dir * dirp = SMB_MALLOC_P ( struct smb_Dir ) ;
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
}
2005-01-29 00:01:58 +03:00
ZERO_STRUCTP ( dirp ) ;
2002-07-15 14:35:28 +04:00
2005-01-29 00:01:58 +03:00
dirp - > conn = conn ;
2002-07-15 14:35:28 +04:00
2005-01-29 00:01:58 +03:00
dirp - > dir_path = SMB_STRDUP ( name ) ;
if ( ! dirp - > dir_path ) {
goto fail ;
}
2005-06-25 07:03:44 +04:00
dirp - > dir = SMB_VFS_OPENDIR ( conn , dirp - > dir_path , mask , attr ) ;
2005-01-29 00:01:58 +03:00
if ( ! dirp - > dir ) {
DEBUG ( 5 , ( " OpenDir: Can't open %s. %s \n " , dirp - > dir_path , strerror ( errno ) ) ) ;
goto fail ;
}
2002-07-15 14:35:28 +04:00
2005-01-29 00:01:58 +03:00
dirp - > name_cache = SMB_CALLOC_ARRAY ( struct name_cache_entry , NAME_CACHE_SIZE ) ;
if ( ! dirp - > name_cache ) {
goto fail ;
}
2002-07-15 14:35:28 +04:00
2005-02-03 05:02:54 +03:00
dirhandles_open + + ;
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 :
2002-09-25 19:19:00 +04:00
2005-01-29 00:01:58 +03:00
if ( dirp ) {
if ( dirp - > dir ) {
SMB_VFS_CLOSEDIR ( conn , dirp - > dir ) ;
2002-07-15 14:35:28 +04:00
}
2005-01-29 00:01:58 +03:00
SAFE_FREE ( dirp - > dir_path ) ;
SAFE_FREE ( dirp - > name_cache ) ;
SAFE_FREE ( dirp ) ;
2002-07-15 14:35:28 +04:00
}
2005-01-29 00:01:58 +03:00
return NULL ;
1996-05-04 11:50:46 +04:00
}
/*******************************************************************
1999-12-13 16:27:58 +03:00
Close a directory .
1996-05-04 11:50:46 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1999-12-13 16:27:58 +03:00
2005-02-01 03:28:20 +03:00
int CloseDir ( struct smb_Dir * dirp )
1996-05-04 11:50:46 +04:00
{
2005-01-29 00:01:58 +03:00
int i , ret = 0 ;
if ( dirp - > dir ) {
ret = SMB_VFS_CLOSEDIR ( dirp - > conn , dirp - > dir ) ;
}
SAFE_FREE ( dirp - > dir_path ) ;
if ( dirp - > name_cache ) {
for ( i = 0 ; i < NAME_CACHE_SIZE ; i + + ) {
SAFE_FREE ( dirp - > name_cache [ i ] . name ) ;
}
}
SAFE_FREE ( dirp - > name_cache ) ;
SAFE_FREE ( dirp ) ;
2005-02-03 05:02:54 +03:00
dirhandles_open - - ;
2005-01-29 00:01:58 +03:00
return ret ;
1996-05-04 11:50:46 +04:00
}
/*******************************************************************
2005-01-29 00:01:58 +03:00
Read from a directory . Also return current offset .
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
2005-02-01 03:28:20 +03:00
const char * ReadDirName ( struct smb_Dir * dirp , long * poffset )
1996-05-04 11:50:46 +04:00
{
2005-01-29 00:01:58 +03:00
const char * n ;
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. */
2005-07-22 00:24:21 +04: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 ) {
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 {
2005-07-22 00:24:21 +04:00
* poffset = dirp - > offset = DOT_DOT_DIRECTORY_OFFSET ;
2005-06-11 03:13:25 +04:00
n = " .. " ;
}
dirp - > file_number + + ;
return n ;
2005-08-22 01:12:27 +04:00
} else if ( * poffset = = END_OF_DIRECTORY_OFFSET ) {
* poffset = dirp - > offset = END_OF_DIRECTORY_OFFSET ;
return NULL ;
2005-06-11 03:13:25 +04:00
} else {
/* A real offset, seek to it. */
SeekDir ( dirp , * poffset ) ;
}
2005-01-29 00:01:58 +03:00
while ( ( n = vfs_readdirname ( conn , dirp - > dir ) ) ) {
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 ' ) ) {
continue ;
}
}
2006-04-08 09:00:04 +04:00
* poffset = dirp - > offset = SMB_VFS_TELLDIR ( conn , dirp - > dir ) ;
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 ;
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 ) ;
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 .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void DirCacheAdd ( struct smb_Dir * dirp , const char * name , long offset )
{
struct name_cache_entry * e ;
dirp - > name_cache_index = ( dirp - > name_cache_index + 1 ) % NAME_CACHE_SIZE ;
e = & dirp - > name_cache [ dirp - > name_cache_index ] ;
SAFE_FREE ( e - > name ) ;
e - > name = SMB_STRDUP ( name ) ;
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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-02-01 21:33:50 +03:00
BOOL SearchDir ( struct smb_Dir * dirp , const char * name , long * poffset )
2005-01-29 00:01:58 +03:00
{
int i ;
const char * entry ;
connection_struct * conn = dirp - > conn ;
/* Search back in the name cache. */
for ( i = dirp - > name_cache_index ; i > = 0 ; i - - ) {
struct name_cache_entry * e = & dirp - > name_cache [ i ] ;
2005-02-01 21:33:50 +03:00
if ( e - > name & & ( conn - > case_sensitive ? ( strcmp ( e - > name , name ) = = 0 ) : strequal ( e - > name , name ) ) ) {
2005-01-29 00:01:58 +03:00
* poffset = e - > offset ;
2005-02-01 03:28:20 +03:00
SeekDir ( dirp , e - > offset ) ;
2005-01-29 00:01:58 +03:00
return True ;
}
}
for ( i = NAME_CACHE_SIZE - 1 ; i > dirp - > name_cache_index ; i - - ) {
struct name_cache_entry * e = & dirp - > name_cache [ i ] ;
2005-02-01 21:33:50 +03:00
if ( e - > name & & ( conn - > case_sensitive ? ( strcmp ( e - > name , name ) = = 0 ) : strequal ( e - > name , name ) ) ) {
2005-01-29 00:01:58 +03:00
* poffset = e - > offset ;
2005-02-01 03:28:20 +03:00
SeekDir ( dirp , e - > offset ) ;
2005-01-29 00:01:58 +03:00
return True ;
}
}
/* 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 ;
2005-01-29 00:01:58 +03:00
while ( ( entry = ReadDirName ( dirp , poffset ) ) ) {
2005-02-01 21:33:50 +03:00
if ( conn - > case_sensitive ? ( strcmp ( entry , name ) = = 0 ) : strequal ( entry , name ) ) {
2005-01-29 00:01:58 +03:00
return True ;
}
}
return False ;
1996-05-04 11:50:46 +04:00
}