2005-11-15 07:38:59 +03:00
/*
Unix SMB / CIFS implementation .
helper functions for SMB2 test suite
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
2007-07-10 06:07:03 +04:00
the Free Software Foundation ; either version 3 of the License , or
2005-11-15 07:38:59 +03:00
( 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
2007-07-10 06:07:03 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2005-11-15 07:38:59 +03:00
*/
# include "includes.h"
# include "libcli/smb2/smb2.h"
# include "libcli/smb2/smb2_calls.h"
# include "lib/cmdline/popt_common.h"
# include "lib/events/events.h"
2005-11-18 09:31:33 +03:00
# include "system/time.h"
2006-03-16 03:23:11 +03:00
# include "librpc/gen_ndr/ndr_security.h"
2007-09-08 16:42:09 +04:00
# include "param/param.h"
2005-11-18 09:31:33 +03:00
/*
close a handle with SMB2
*/
NTSTATUS smb2_util_close ( struct smb2_tree * tree , struct smb2_handle h )
{
struct smb2_close c ;
ZERO_STRUCT ( c ) ;
2006-05-20 14:46:38 +04:00
c . in . file . handle = h ;
2005-11-18 09:31:33 +03:00
return smb2_close ( tree , & c ) ;
}
/*
unlink a file with SMB2
*/
NTSTATUS smb2_util_unlink ( struct smb2_tree * tree , const char * fname )
{
struct smb2_create io ;
NTSTATUS status ;
ZERO_STRUCT ( io ) ;
io . in . access_mask = SEC_RIGHTS_FILE_ALL ;
io . in . file_attr = FILE_ATTRIBUTE_NORMAL ;
io . in . open_disposition = NTCREATEX_DISP_OPEN ;
io . in . share_access =
NTCREATEX_SHARE_ACCESS_DELETE |
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE ;
io . in . create_options = NTCREATEX_OPTIONS_DELETE_ON_CLOSE ;
io . in . fname = fname ;
status = smb2_create ( tree , tree , & io ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ) {
return NT_STATUS_OK ;
}
NT_STATUS_NOT_OK_RETURN ( status ) ;
2006-05-20 14:46:38 +04:00
return smb2_util_close ( tree , io . out . file . handle ) ;
2005-11-18 09:31:33 +03:00
}
/*
write to a file on SMB2
*/
NTSTATUS smb2_util_write ( struct smb2_tree * tree ,
struct smb2_handle handle ,
const void * buf , off_t offset , size_t size )
{
struct smb2_write w ;
ZERO_STRUCT ( w ) ;
2006-05-20 14:46:38 +04:00
w . in . file . handle = handle ;
2005-11-18 09:31:33 +03:00
w . in . offset = offset ;
w . in . data = data_blob_const ( buf , size ) ;
return smb2_write ( tree , & w ) ;
}
/*
2005-11-18 12:51:13 +03:00
create a complex file / dir using the SMB2 protocol
2005-11-18 09:31:33 +03:00
*/
2005-11-18 12:51:13 +03:00
static NTSTATUS smb2_create_complex ( struct smb2_tree * tree , const char * fname ,
struct smb2_handle * handle , BOOL dir )
2005-11-18 09:31:33 +03:00
{
2005-11-18 12:25:25 +03:00
TALLOC_CTX * tmp_ctx = talloc_new ( tree ) ;
2005-11-18 09:31:33 +03:00
char buf [ 7 ] = " abc " ;
struct smb2_create io ;
union smb_setfileinfo setfile ;
union smb_fileinfo fileinfo ;
time_t t = ( time ( NULL ) & ~ 1 ) ;
NTSTATUS status ;
2005-11-18 12:51:13 +03:00
smb2_util_unlink ( tree , fname ) ;
2005-11-18 09:31:33 +03:00
ZERO_STRUCT ( io ) ;
2005-11-18 14:45:24 +03:00
io . in . access_mask = SEC_FLAG_MAXIMUM_ALLOWED ;
2005-11-18 09:31:33 +03:00
io . in . file_attr = FILE_ATTRIBUTE_NORMAL ;
io . in . open_disposition = NTCREATEX_DISP_OVERWRITE_IF ;
io . in . share_access =
NTCREATEX_SHARE_ACCESS_DELETE |
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE ;
io . in . create_options = 0 ;
io . in . fname = fname ;
2005-11-18 12:51:13 +03:00
if ( dir ) {
io . in . create_options = NTCREATEX_OPTIONS_DIRECTORY ;
io . in . share_access & = ~ NTCREATEX_SHARE_ACCESS_DELETE ;
io . in . file_attr = FILE_ATTRIBUTE_DIRECTORY ;
io . in . open_disposition = NTCREATEX_DISP_CREATE ;
}
2005-11-18 09:31:33 +03:00
2005-11-18 12:25:25 +03:00
if ( strchr ( fname , ' : ' ) = = NULL ) {
/* setup some EAs */
io . in . eas . num_eas = 2 ;
io . in . eas . eas = talloc_array ( tmp_ctx , struct ea_struct , 2 ) ;
io . in . eas . eas [ 0 ] . flags = 0 ;
io . in . eas . eas [ 0 ] . name . s = " EAONE " ;
io . in . eas . eas [ 0 ] . value = data_blob_talloc ( tmp_ctx , " VALUE1 " , 6 ) ;
io . in . eas . eas [ 1 ] . flags = 0 ;
io . in . eas . eas [ 1 ] . name . s = " SECONDEA " ;
io . in . eas . eas [ 1 ] . value = data_blob_talloc ( tmp_ctx , " ValueTwo " , 8 ) ;
}
status = smb2_create ( tree , tmp_ctx , & io ) ;
talloc_free ( tmp_ctx ) ;
2005-11-18 09:31:33 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2006-05-20 14:46:38 +04:00
* handle = io . out . file . handle ;
2005-11-18 09:31:33 +03:00
2005-11-18 12:51:13 +03:00
if ( ! dir ) {
status = smb2_util_write ( tree , * handle , buf , 0 , sizeof ( buf ) ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
}
2005-11-18 09:31:33 +03:00
/* make sure all the timestamps aren't the same, and are also
in different DST zones */
setfile . generic . level = RAW_SFILEINFO_BASIC_INFORMATION ;
2006-03-13 01:48:25 +03:00
setfile . generic . in . file . handle = * handle ;
2005-11-18 09:31:33 +03:00
2006-07-01 18:20:14 +04:00
unix_to_nt_time ( & setfile . basic_info . in . create_time , t + 9 * 30 * 24 * 60 * 60 ) ;
unix_to_nt_time ( & setfile . basic_info . in . access_time , t + 6 * 30 * 24 * 60 * 60 ) ;
unix_to_nt_time ( & setfile . basic_info . in . write_time , t + 3 * 30 * 24 * 60 * 60 ) ;
unix_to_nt_time ( & setfile . basic_info . in . change_time , t + 1 * 30 * 24 * 60 * 60 ) ;
2005-11-18 09:31:33 +03:00
setfile . basic_info . in . attrib = FILE_ATTRIBUTE_NORMAL ;
status = smb2_setinfo_file ( tree , & setfile ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to setup file times - %s \n " , nt_errstr ( status ) ) ;
2006-07-01 18:20:14 +04:00
return status ;
2005-11-18 09:31:33 +03:00
}
/* make sure all the timestamps aren't the same */
2006-07-08 15:05:24 +04:00
fileinfo . generic . level = RAW_FILEINFO_SMB2_ALL_INFORMATION ;
2006-03-13 01:48:25 +03:00
fileinfo . generic . in . file . handle = * handle ;
2005-11-18 09:31:33 +03:00
status = smb2_getinfo_file ( tree , tree , & fileinfo ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to query file times - %s \n " , nt_errstr ( status ) ) ;
2006-07-01 18:20:14 +04:00
return status ;
2005-11-18 09:31:33 +03:00
}
2006-07-01 18:20:14 +04:00
# define CHECK_TIME(field) do {\
2006-07-08 15:05:24 +04:00
if ( setfile . basic_info . in . field ! = fileinfo . all_info2 . out . field ) { \
2006-07-01 18:20:14 +04:00
printf ( " (%s) " # field " not setup correctly: %s(%llu) => %s(%llu) \n " , \
__location__ , \
nt_time_string ( tree , setfile . basic_info . in . field ) , \
2006-09-09 14:05:58 +04:00
( unsigned long long ) setfile . basic_info . in . field , \
2006-07-01 18:20:14 +04:00
nt_time_string ( tree , fileinfo . basic_info . out . field ) , \
2006-09-09 14:05:58 +04:00
( unsigned long long ) fileinfo . basic_info . out . field ) ; \
2006-07-01 18:20:14 +04:00
status = NT_STATUS_INVALID_PARAMETER ; \
} \
} while ( 0 )
CHECK_TIME ( create_time ) ;
CHECK_TIME ( access_time ) ;
CHECK_TIME ( write_time ) ;
CHECK_TIME ( change_time ) ;
return status ;
2005-11-18 09:31:33 +03:00
}
2005-11-15 07:38:59 +03:00
2005-11-18 12:51:13 +03:00
/*
create a complex file using the SMB2 protocol
*/
NTSTATUS smb2_create_complex_file ( struct smb2_tree * tree , const char * fname ,
struct smb2_handle * handle )
{
return smb2_create_complex ( tree , fname , handle , False ) ;
}
/*
create a complex dir using the SMB2 protocol
*/
NTSTATUS smb2_create_complex_dir ( struct smb2_tree * tree , const char * fname ,
struct smb2_handle * handle )
{
return smb2_create_complex ( tree , fname , handle , True ) ;
}
2005-11-15 07:38:59 +03:00
/*
show lots of information about a file
*/
void torture_smb2_all_info ( struct smb2_tree * tree , struct smb2_handle handle )
{
NTSTATUS status ;
TALLOC_CTX * tmp_ctx = talloc_new ( tree ) ;
2005-11-17 14:06:13 +03:00
union smb_fileinfo io ;
2005-11-15 07:38:59 +03:00
2005-11-17 14:06:13 +03:00
io . generic . level = RAW_FILEINFO_SMB2_ALL_INFORMATION ;
2006-03-13 01:48:25 +03:00
io . generic . in . file . handle = handle ;
2005-11-17 14:06:13 +03:00
status = smb2_getinfo_file ( tree , tmp_ctx , & io ) ;
2005-11-15 07:38:59 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " getinfo failed - %s \n " , nt_errstr ( status ) ) ) ;
talloc_free ( tmp_ctx ) ;
return ;
}
2005-11-18 12:51:13 +03:00
d_printf ( " all_info for '%s' \n " , io . all_info2 . out . fname . s ) ;
2005-11-17 14:06:13 +03:00
d_printf ( " \t create_time: %s \n " , nt_time_string ( tmp_ctx , io . all_info2 . out . create_time ) ) ;
d_printf ( " \t access_time: %s \n " , nt_time_string ( tmp_ctx , io . all_info2 . out . access_time ) ) ;
d_printf ( " \t write_time: %s \n " , nt_time_string ( tmp_ctx , io . all_info2 . out . write_time ) ) ;
d_printf ( " \t change_time: %s \n " , nt_time_string ( tmp_ctx , io . all_info2 . out . change_time ) ) ;
d_printf ( " \t attrib: 0x%x \n " , io . all_info2 . out . attrib ) ;
d_printf ( " \t unknown1: 0x%x \n " , io . all_info2 . out . unknown1 ) ;
2005-11-30 05:08:15 +03:00
d_printf ( " \t alloc_size: %llu \n " , ( long long ) io . all_info2 . out . alloc_size ) ;
d_printf ( " \t size: %llu \n " , ( long long ) io . all_info2 . out . size ) ;
2005-11-17 14:06:13 +03:00
d_printf ( " \t nlink: %u \n " , io . all_info2 . out . nlink ) ;
d_printf ( " \t delete_pending: %u \n " , io . all_info2 . out . delete_pending ) ;
d_printf ( " \t directory: %u \n " , io . all_info2 . out . directory ) ;
2005-11-30 05:08:15 +03:00
d_printf ( " \t file_id: %llu \n " , ( long long ) io . all_info2 . out . file_id ) ;
2005-11-17 14:06:13 +03:00
d_printf ( " \t ea_size: %u \n " , io . all_info2 . out . ea_size ) ;
d_printf ( " \t access_mask: 0x%08x \n " , io . all_info2 . out . access_mask ) ;
2005-11-30 05:08:15 +03:00
d_printf ( " \t position: 0x%llx \n " , ( long long ) io . all_info2 . out . position ) ;
d_printf ( " \t mode: 0x%llx \n " , ( long long ) io . all_info2 . out . mode ) ;
2005-11-15 07:38:59 +03:00
2005-11-17 07:03:31 +03:00
/* short name, if any */
2005-11-17 14:06:13 +03:00
io . generic . level = RAW_FILEINFO_ALT_NAME_INFORMATION ;
status = smb2_getinfo_file ( tree , tmp_ctx , & io ) ;
2005-11-17 07:03:31 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
2005-11-17 14:06:13 +03:00
d_printf ( " \t short name: '%s' \n " , io . alt_name_info . out . fname . s ) ;
2005-11-17 07:03:31 +03:00
}
2005-11-16 07:35:49 +03:00
/* the EAs, if any */
2005-11-17 14:06:13 +03:00
io . generic . level = RAW_FILEINFO_SMB2_ALL_EAS ;
status = smb2_getinfo_file ( tree , tmp_ctx , & io ) ;
2005-11-16 07:35:49 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
int i ;
2005-11-17 14:06:13 +03:00
for ( i = 0 ; i < io . all_eas . out . num_eas ; i + + ) {
2005-11-16 07:35:49 +03:00
d_printf ( " \t EA[%d] flags=%d len=%d '%s' \n " , i ,
2005-11-17 14:06:13 +03:00
io . all_eas . out . eas [ i ] . flags ,
( int ) io . all_eas . out . eas [ i ] . value . length ,
io . all_eas . out . eas [ i ] . name . s ) ;
2005-11-16 07:35:49 +03:00
}
}
/* streams, if available */
2005-11-17 14:06:13 +03:00
io . generic . level = RAW_FILEINFO_STREAM_INFORMATION ;
status = smb2_getinfo_file ( tree , tmp_ctx , & io ) ;
2005-11-16 07:35:49 +03:00
if ( NT_STATUS_IS_OK ( status ) ) {
int i ;
2005-11-17 14:06:13 +03:00
for ( i = 0 ; i < io . stream_info . out . num_streams ; i + + ) {
2005-11-16 07:35:49 +03:00
d_printf ( " \t stream %d: \n " , i ) ;
d_printf ( " \t \t size %ld \n " ,
2005-11-17 14:06:13 +03:00
( long ) io . stream_info . out . streams [ i ] . size ) ;
2005-11-16 07:35:49 +03:00
d_printf ( " \t \t alloc size %ld \n " ,
2005-11-17 14:06:13 +03:00
( long ) io . stream_info . out . streams [ i ] . alloc_size ) ;
d_printf ( " \t \t name %s \n " , io . stream_info . out . streams [ i ] . stream_name . s ) ;
2005-11-16 07:35:49 +03:00
}
}
2005-11-19 08:55:08 +03:00
if ( DEBUGLVL ( 1 ) ) {
/* the security descriptor */
io . query_secdesc . level = RAW_FILEINFO_SEC_DESC ;
2006-03-10 23:49:20 +03:00
io . query_secdesc . in . secinfo_flags =
2005-11-19 08:55:08 +03:00
SECINFO_OWNER | SECINFO_GROUP |
SECINFO_DACL ;
status = smb2_getinfo_file ( tree , tmp_ctx , & io ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
NDR_PRINT_DEBUG ( security_descriptor , io . query_secdesc . out . sd ) ;
}
2005-11-18 13:07:14 +03:00
}
2005-11-15 07:38:59 +03:00
talloc_free ( tmp_ctx ) ;
}
/*
open a smb2 connection
*/
BOOL torture_smb2_connection ( TALLOC_CTX * mem_ctx , struct smb2_tree * * tree )
{
NTSTATUS status ;
const char * host = lp_parm_string ( - 1 , " torture " , " host " ) ;
const char * share = lp_parm_string ( - 1 , " torture " , " share " ) ;
struct cli_credentials * credentials = cmdline_credentials ;
status = smb2_connect ( mem_ctx , host , share , credentials , tree ,
event_context_find ( mem_ctx ) ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
printf ( " Failed to connect to SMB2 share \\ \\ %s \\ %s - %s \n " ,
host , share , nt_errstr ( status ) ) ;
return False ;
}
return True ;
}
/*
create and return a handle to a test file
*/
NTSTATUS torture_smb2_testfile ( struct smb2_tree * tree , const char * fname ,
struct smb2_handle * handle )
{
struct smb2_create io ;
struct smb2_read r ;
NTSTATUS status ;
ZERO_STRUCT ( io ) ;
io . in . oplock_flags = 0 ;
io . in . access_mask = SEC_RIGHTS_FILE_ALL ;
io . in . file_attr = FILE_ATTRIBUTE_NORMAL ;
io . in . open_disposition = NTCREATEX_DISP_OPEN_IF ;
io . in . share_access =
NTCREATEX_SHARE_ACCESS_DELETE |
NTCREATEX_SHARE_ACCESS_READ |
NTCREATEX_SHARE_ACCESS_WRITE ;
2005-11-18 12:25:25 +03:00
io . in . create_options = 0 ;
2005-11-15 07:38:59 +03:00
io . in . fname = fname ;
2005-11-16 14:01:15 +03:00
status = smb2_create ( tree , tree , & io ) ;
2005-11-15 07:38:59 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2006-05-20 14:46:38 +04:00
* handle = io . out . file . handle ;
2005-11-15 07:38:59 +03:00
ZERO_STRUCT ( r ) ;
2006-05-20 14:46:38 +04:00
r . in . file . handle = * handle ;
2005-11-15 07:38:59 +03:00
r . in . length = 5 ;
r . in . offset = 0 ;
smb2_read ( tree , tree , & r ) ;
return NT_STATUS_OK ;
}
/*
create and return a handle to a test directory
*/
NTSTATUS torture_smb2_testdir ( struct smb2_tree * tree , const char * fname ,
struct smb2_handle * handle )
{
struct smb2_create io ;
NTSTATUS status ;
ZERO_STRUCT ( io ) ;
io . in . oplock_flags = 0 ;
io . in . access_mask = SEC_RIGHTS_DIR_ALL ;
io . in . file_attr = FILE_ATTRIBUTE_DIRECTORY ;
io . in . open_disposition = NTCREATEX_DISP_OPEN_IF ;
2005-11-17 14:06:13 +03:00
io . in . share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_WRITE | NTCREATEX_SHARE_ACCESS_DELETE ;
2005-11-15 07:38:59 +03:00
io . in . create_options = NTCREATEX_OPTIONS_DIRECTORY ;
io . in . fname = fname ;
2005-11-16 14:01:15 +03:00
status = smb2_create ( tree , tree , & io ) ;
2005-11-15 07:38:59 +03:00
NT_STATUS_NOT_OK_RETURN ( status ) ;
2006-05-20 14:46:38 +04:00
* handle = io . out . file . handle ;
2005-11-15 07:38:59 +03:00
return NT_STATUS_OK ;
}
/*
create a complex file using the old SMB protocol , to make it easier to
find fields in SMB2 getinfo levels
*/
2005-11-18 12:51:13 +03:00
NTSTATUS torture_setup_complex_file ( struct smb2_tree * tree , const char * fname )
2005-11-15 07:38:59 +03:00
{
2005-11-18 12:51:13 +03:00
struct smb2_handle handle ;
NTSTATUS status = smb2_create_complex_file ( tree , fname , & handle ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
return smb2_util_close ( tree , handle ) ;
2005-11-15 07:38:59 +03:00
}
2005-11-18 12:51:13 +03:00
2005-11-15 07:38:59 +03:00
/*
2005-11-18 12:51:13 +03:00
create a complex dir using the old SMB protocol , to make it easier to
2005-11-15 07:38:59 +03:00
find fields in SMB2 getinfo levels
*/
2005-11-18 12:51:13 +03:00
NTSTATUS torture_setup_complex_dir ( struct smb2_tree * tree , const char * fname )
2005-11-15 07:38:59 +03:00
{
2005-11-18 12:51:13 +03:00
struct smb2_handle handle ;
NTSTATUS status = smb2_create_complex_dir ( tree , fname , & handle ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
return smb2_util_close ( tree , handle ) ;
2005-11-15 07:38:59 +03:00
}
2005-11-18 12:51:13 +03:00
2005-11-19 08:55:08 +03:00
/*
return a handle to the root of the share
*/
NTSTATUS smb2_util_roothandle ( struct smb2_tree * tree , struct smb2_handle * handle )
{
struct smb2_create io ;
NTSTATUS status ;
ZERO_STRUCT ( io ) ;
io . in . oplock_flags = 0 ;
io . in . access_mask = SEC_STD_SYNCHRONIZE | SEC_DIR_READ_ATTRIBUTE | SEC_DIR_LIST ;
io . in . file_attr = 0 ;
io . in . open_disposition = NTCREATEX_DISP_OPEN ;
io . in . share_access = NTCREATEX_SHARE_ACCESS_READ | NTCREATEX_SHARE_ACCESS_DELETE ;
io . in . create_options = NTCREATEX_OPTIONS_ASYNC_ALERT ;
io . in . fname = " " ;
status = smb2_create ( tree , tree , & io ) ;
NT_STATUS_NOT_OK_RETURN ( status ) ;
2006-05-20 14:46:38 +04:00
* handle = io . out . file . handle ;
2005-11-19 08:55:08 +03:00
return NT_STATUS_OK ;
}