2008-05-20 05:58:04 +04:00
/*
Unix SMB / CIFS implementation .
SMB2 client utility functions
Copyright ( C ) Andrew Tridgell 2005
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 3 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 , see < http : //www.gnu.org/licenses/>.
*/
# include "includes.h"
# include "libcli/raw/libcliraw.h"
# include "libcli/raw/raw_proto.h"
# include "libcli/smb2/smb2.h"
# include "libcli/smb2/smb2_calls.h"
# include "libcli/smb_composite/smb_composite.h"
2009-07-02 00:30:12 +04:00
# include "librpc/gen_ndr/ndr_security.h"
2008-05-20 05:58:04 +04:00
/*
simple close wrapper with SMB2
*/
NTSTATUS smb2_util_close ( struct smb2_tree * tree , struct smb2_handle h )
{
struct smb2_close c ;
ZERO_STRUCT ( c ) ;
c . in . file . handle = h ;
return smb2_close ( tree , & c ) ;
}
/*
unlink a file with SMB2
*/
NTSTATUS smb2_util_unlink ( struct smb2_tree * tree , const char * fname )
{
union smb_unlink io ;
ZERO_STRUCT ( io ) ;
io . unlink . in . pattern = fname ;
return smb2_composite_unlink ( tree , & io ) ;
}
/*
rmdir with SMB2
*/
NTSTATUS smb2_util_rmdir ( struct smb2_tree * tree , const char * dname )
{
struct smb_rmdir io ;
ZERO_STRUCT ( io ) ;
io . in . path = dname ;
return smb2_composite_rmdir ( tree , & io ) ;
}
/*
mkdir with SMB2
*/
NTSTATUS smb2_util_mkdir ( struct smb2_tree * tree , const char * dname )
{
union smb_mkdir io ;
ZERO_STRUCT ( io ) ;
io . mkdir . level = RAW_MKDIR_MKDIR ;
io . mkdir . in . path = dname ;
return smb2_composite_mkdir ( tree , & io ) ;
}
2008-05-20 07:37:51 +04:00
/*
set file attribute with SMB2
*/
NTSTATUS smb2_util_setatr ( struct smb2_tree * tree , const char * name , uint32_t attrib )
{
2022-08-14 19:51:30 +03:00
struct smb2_create cr = { 0 } ;
struct smb2_handle h1 = { { 0 } } ;
union smb_setfileinfo setinfo ;
NTSTATUS status ;
cr = ( struct smb2_create ) {
. in . desired_access = SEC_FILE_WRITE_ATTRIBUTE ,
. in . share_access = NTCREATEX_SHARE_ACCESS_MASK ,
. in . create_disposition = FILE_OPEN ,
. in . fname = name ,
} ;
status = smb2_create ( tree , tree , & cr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
h1 = cr . out . file . handle ;
setinfo = ( union smb_setfileinfo ) {
. basic_info . level = RAW_SFILEINFO_BASIC_INFORMATION ,
. basic_info . in . file . handle = h1 ,
. basic_info . in . attrib = attrib ,
} ;
status = smb2_setinfo_file ( tree , & setinfo ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
smb2_util_close ( tree , h1 ) ;
return status ;
}
smb2_util_close ( tree , h1 ) ;
return NT_STATUS_OK ;
2008-05-20 07:37:51 +04:00
}
2019-12-10 17:47:12 +03:00
/*
get file attribute with SMB2
*/
NTSTATUS smb2_util_getatr ( struct smb2_tree * tree , const char * fname ,
uint16_t * attr , size_t * size , time_t * t )
{
union smb_fileinfo parms ;
NTSTATUS status ;
struct smb2_create create_io = { 0 } ;
create_io . in . desired_access = SEC_FILE_READ_ATTRIBUTE ;
create_io . in . share_access = NTCREATEX_SHARE_ACCESS_NONE ;
create_io . in . create_disposition = FILE_OPEN ;
create_io . in . fname = fname ;
status = smb2_create ( tree , tree , & create_io ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
ZERO_STRUCT ( parms ) ;
parms . all_info2 . level = RAW_FILEINFO_SMB2_ALL_INFORMATION ;
parms . all_info2 . in . file . handle = create_io . out . file . handle ;
status = smb2_getinfo_file ( tree , tree , & parms ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
status = smb2_util_close ( tree , create_io . out . file . handle ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
if ( size ) {
* size = parms . all_info2 . out . size ;
}
if ( t ) {
* t = parms . all_info2 . out . write_time ;
}
if ( attr ) {
* attr = parms . all_info2 . out . attrib ;
}
return status ;
}
2008-05-20 05:58:04 +04:00
/*
recursively descend a tree deleting all files
returns the number of files deleted , or - 1 on error
*/
int smb2_deltree ( struct smb2_tree * tree , const char * dname )
{
NTSTATUS status ;
uint32_t total_deleted = 0 ;
2010-01-05 20:42:54 +03:00
unsigned int count , i ;
2008-05-20 05:58:04 +04:00
union smb_search_data * list ;
TALLOC_CTX * tmp_ctx = talloc_new ( tree ) ;
struct smb2_find f ;
struct smb2_create create_parm ;
2009-08-05 09:05:13 +04:00
bool did_delete ;
2008-05-20 05:58:04 +04:00
/* it might be a file */
status = smb2_util_unlink ( tree , dname ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
talloc_free ( tmp_ctx ) ;
return 1 ;
}
if ( NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_PATH_NOT_FOUND ) | |
NT_STATUS_EQUAL ( status , NT_STATUS_NO_SUCH_FILE ) ) {
talloc_free ( tmp_ctx ) ;
return 0 ;
}
2008-05-27 08:06:27 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_CANNOT_DELETE ) ) {
/* it could be read-only */
2019-07-29 14:44:26 +03:00
smb2_util_setatr ( tree , dname , FILE_ATTRIBUTE_NORMAL ) ;
2008-05-27 08:06:27 +04:00
status = smb2_util_unlink ( tree , dname ) ;
}
if ( NT_STATUS_IS_OK ( status ) ) {
talloc_free ( tmp_ctx ) ;
return 1 ;
}
2008-05-20 05:58:04 +04:00
ZERO_STRUCT ( create_parm ) ;
2008-09-25 04:19:36 +04:00
create_parm . in . desired_access = SEC_FILE_READ_DATA ;
2008-05-20 05:58:04 +04:00
create_parm . in . share_access =
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE ;
create_parm . in . create_options = NTCREATEX_OPTIONS_DIRECTORY ;
create_parm . in . create_disposition = NTCREATEX_DISP_OPEN ;
create_parm . in . fname = dname ;
status = smb2_create ( tree , tmp_ctx , & create_parm ) ;
if ( NT_STATUS_IS_ERR ( status ) ) {
DEBUG ( 2 , ( " Failed to open %s - %s \n " , dname , nt_errstr ( status ) ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
2009-08-05 09:05:13 +04:00
do {
did_delete = false ;
ZERO_STRUCT ( f ) ;
f . in . file . handle = create_parm . out . file . handle ;
f . in . max_response_size = 0x10000 ;
f . in . level = SMB2_FIND_NAME_INFO ;
f . in . pattern = " * " ;
status = smb2_find_level ( tree , tmp_ctx , & f , & count , & list ) ;
if ( NT_STATUS_IS_ERR ( status ) ) {
DEBUG ( 2 , ( " Failed to list %s - %s \n " ,
dname , nt_errstr ( status ) ) ) ;
smb2_util_close ( tree , create_parm . out . file . handle ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
2008-05-20 05:58:04 +04:00
}
2009-08-05 09:05:13 +04:00
for ( i = 0 ; i < count ; i + + ) {
char * name ;
if ( strcmp ( " . " , list [ i ] . name_info . name . s ) = = 0 | |
strcmp ( " .. " , list [ i ] . name_info . name . s ) = = 0 ) {
continue ;
}
name = talloc_asprintf ( tmp_ctx , " %s \\ %s " , dname , list [ i ] . name_info . name . s ) ;
2008-05-20 07:37:51 +04:00
status = smb2_util_unlink ( tree , name ) ;
2009-08-05 09:05:13 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_CANNOT_DELETE ) ) {
/* it could be read-only */
2019-07-29 14:44:26 +03:00
smb2_util_setatr ( tree , name , FILE_ATTRIBUTE_NORMAL ) ;
2009-08-05 09:05:13 +04:00
status = smb2_util_unlink ( tree , name ) ;
}
if ( NT_STATUS_EQUAL ( status , NT_STATUS_FILE_IS_A_DIRECTORY ) ) {
int ret ;
ret = smb2_deltree ( tree , name ) ;
if ( ret > 0 ) total_deleted + = ret ;
}
talloc_free ( name ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
total_deleted + + ;
did_delete = true ;
}
2008-05-20 07:37:51 +04:00
}
2009-08-05 09:05:13 +04:00
} while ( did_delete ) ;
2008-05-20 05:58:04 +04:00
smb2_util_close ( tree , create_parm . out . file . handle ) ;
status = smb2_util_rmdir ( tree , dname ) ;
2008-09-23 09:16:46 +04:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_CANNOT_DELETE ) ) {
/* it could be read-only */
2019-07-29 14:44:26 +03:00
smb2_util_setatr ( tree , dname , FILE_ATTRIBUTE_NORMAL ) ;
2008-09-23 09:16:46 +04:00
status = smb2_util_rmdir ( tree , dname ) ;
}
2008-05-20 05:58:04 +04:00
if ( NT_STATUS_IS_ERR ( status ) ) {
DEBUG ( 2 , ( " Failed to delete %s - %s \n " ,
dname , nt_errstr ( status ) ) ) ;
talloc_free ( tmp_ctx ) ;
return - 1 ;
}
talloc_free ( tmp_ctx ) ;
return total_deleted ;
}
2009-07-31 02:10:50 +04:00
/*
check if two SMB2 file handles are the same
*/
bool smb2_util_handle_equal ( const struct smb2_handle h1 ,
const struct smb2_handle h2 )
{
return ( h1 . data [ 0 ] = = h2 . data [ 0 ] ) & & ( h1 . data [ 1 ] = = h2 . data [ 1 ] ) ;
}
2013-12-04 17:01:47 +04:00
bool smb2_util_handle_empty ( const struct smb2_handle h )
{
struct smb2_handle empty ;
ZERO_STRUCT ( empty ) ;
return smb2_util_handle_equal ( h , empty ) ;
}
2020-01-13 19:19:51 +03:00
/****************************************************************************
send a qpathinfo SMB_QUERY_FILE_ALT_NAME_INFO call
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS smb2_qpathinfo_alt_name ( TALLOC_CTX * ctx , struct smb2_tree * tree ,
const char * fname , const char * * alt_name )
{
union smb_fileinfo parms ;
TALLOC_CTX * mem_ctx ;
NTSTATUS status ;
struct smb2_create create_io = { 0 } ;
mem_ctx = talloc_new ( ctx ) ;
if ( ! mem_ctx ) {
return NT_STATUS_NO_MEMORY ;
}
create_io . in . desired_access = SEC_FILE_READ_ATTRIBUTE ;
create_io . in . share_access = NTCREATEX_SHARE_ACCESS_NONE ;
create_io . in . create_disposition = FILE_OPEN ;
create_io . in . fname = fname ;
status = smb2_create ( tree , mem_ctx , & create_io ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( mem_ctx ) ;
return status ;
}
parms . alt_name_info . level = RAW_FILEINFO_SMB2_ALT_NAME_INFORMATION ;
parms . alt_name_info . in . file . handle = create_io . out . file . handle ;
status = smb2_getinfo_file ( tree , mem_ctx , & parms ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( mem_ctx ) ;
return status ;
}
status = smb2_util_close ( tree , create_io . out . file . handle ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
talloc_free ( mem_ctx ) ;
return status ;
}
if ( ! parms . alt_name_info . out . fname . s ) {
* alt_name = talloc_strdup ( ctx , " " ) ;
} else {
* alt_name = talloc_strdup ( ctx ,
parms . alt_name_info . out . fname . s ) ;
}
talloc_free ( mem_ctx ) ;
return NT_STATUS_OK ;
}