2022-03-16 01:29:59 +03:00
/*
Unix SMB / CIFS implementation .
Main SMB reply routines
Copyright ( C ) Andrew Tridgell 1992 - 1998
Copyright ( C ) Andrew Bartlett 2001
Copyright ( C ) Jeremy Allison 1992 - 2007.
Copyright ( C ) Volker Lendecke 2007
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/>.
*/
/*
This file handles most of the reply_ calls that the server
makes to handle specific protocols
*/
# include "includes.h"
# include "libsmb/namequery.h"
# include "system/filesys.h"
# include "printing.h"
# include "locking/share_mode_lock.h"
# include "smbd/smbd.h"
# include "smbd/globals.h"
# include "smbd/smbXsrv_open.h"
# include "fake_file.h"
# include "rpc_client/rpc_client.h"
# include "../librpc/gen_ndr/ndr_spoolss_c.h"
# include "rpc_client/cli_spoolss.h"
# include "rpc_client/init_spoolss.h"
# include "rpc_server/rpc_ncacn_np.h"
# include "libcli/security/security.h"
# include "libsmb/nmblib.h"
# include "auth.h"
# include "smbprofile.h"
# include "../lib/tsocket/tsocket.h"
# include "lib/util/tevent_ntstatus.h"
# include "libcli/smb/smb_signing.h"
# include "lib/util/sys_rw_data.h"
# include "librpc/gen_ndr/open_files.h"
# include "smb1_utils.h"
# include "libcli/smb/smb2_posix.h"
# include "lib/util/string_wrappers.h"
# include "source3/printing/rap_jobid.h"
# include "source3/lib/substitute.h"
/****************************************************************************
Ensure we check the path in * exactly * the same way as W2K for a findfirst / findnext
path or anything including wildcards .
We ' re assuming here that ' / ' is not the second byte in any multibyte char
set ( a safe assumption ) . ' \\ ' * may * be the second byte in a multibyte char
set .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* Custom version for processing POSIX paths. */
# define IS_PATH_SEP(c,posix_only) ((c) == ' / ' || (!(posix_only) && (c) == '\\'))
static NTSTATUS check_path_syntax_internal ( char * path ,
bool posix_path )
{
char * d = path ;
const char * s = path ;
NTSTATUS ret = NT_STATUS_OK ;
bool start_of_name_component = True ;
bool stream_started = false ;
bool last_component_contains_wcard = false ;
while ( * s ) {
if ( stream_started ) {
switch ( * s ) {
case ' / ' :
case ' \\ ' :
return NT_STATUS_OBJECT_NAME_INVALID ;
case ' : ' :
if ( s [ 1 ] = = ' \0 ' ) {
return NT_STATUS_OBJECT_NAME_INVALID ;
}
if ( strchr_m ( & s [ 1 ] , ' : ' ) ) {
return NT_STATUS_OBJECT_NAME_INVALID ;
}
break ;
}
}
if ( ( * s = = ' : ' ) & & ! posix_path & & ! stream_started ) {
if ( last_component_contains_wcard ) {
return NT_STATUS_OBJECT_NAME_INVALID ;
}
/* Stream names allow more characters than file names.
We ' re overloading posix_path here to allow a wider
range of characters . If stream_started is true this
is still a Windows path even if posix_path is true .
JRA .
*/
stream_started = true ;
start_of_name_component = false ;
posix_path = true ;
if ( s [ 1 ] = = ' \0 ' ) {
return NT_STATUS_OBJECT_NAME_INVALID ;
}
}
if ( ! stream_started & & IS_PATH_SEP ( * s , posix_path ) ) {
/*
* Safe to assume is not the second part of a mb char
* as this is handled below .
*/
/* Eat multiple '/' or '\\' */
while ( IS_PATH_SEP ( * s , posix_path ) ) {
s + + ;
}
if ( ( d ! = path ) & & ( * s ! = ' \0 ' ) ) {
/* We only care about non-leading or trailing '/' or '\\' */
* d + + = ' / ' ;
}
start_of_name_component = True ;
/* New component. */
last_component_contains_wcard = false ;
continue ;
}
if ( start_of_name_component ) {
if ( ( s [ 0 ] = = ' . ' ) & & ( s [ 1 ] = = ' . ' ) & & ( IS_PATH_SEP ( s [ 2 ] , posix_path ) | | s [ 2 ] = = ' \0 ' ) ) {
/* Uh oh - "/../" or "\\..\\" or "/..\0" or "\\..\0" ! */
/*
* No mb char starts with ' . ' so we ' re safe checking the directory separator here .
*/
/* If we just added a '/' - delete it */
if ( ( d > path ) & & ( * ( d - 1 ) = = ' / ' ) ) {
* ( d - 1 ) = ' \0 ' ;
d - - ;
}
/* Are we at the start ? Can't go back further if so. */
if ( d < = path ) {
ret = NT_STATUS_OBJECT_PATH_SYNTAX_BAD ;
break ;
}
/* Go back one level... */
/* We know this is safe as '/' cannot be part of a mb sequence. */
/* NOTE - if this assumption is invalid we are not in good shape... */
/* Decrement d first as d points to the *next* char to write into. */
for ( d - - ; d > path ; d - - ) {
if ( * d = = ' / ' )
break ;
}
s + = 2 ; /* Else go past the .. */
/* We're still at the start of a name component, just the previous one. */
continue ;
} else if ( ( s [ 0 ] = = ' . ' ) & & ( ( s [ 1 ] = = ' \0 ' ) | | IS_PATH_SEP ( s [ 1 ] , posix_path ) ) ) {
if ( posix_path ) {
/* Eat the '.' */
s + + ;
continue ;
}
}
}
if ( ! ( * s & 0x80 ) ) {
if ( ! posix_path ) {
if ( * s < = 0x1f | | * s = = ' | ' ) {
return NT_STATUS_OBJECT_NAME_INVALID ;
}
switch ( * s ) {
case ' * ' :
case ' ? ' :
case ' < ' :
case ' > ' :
case ' " ' :
last_component_contains_wcard = true ;
break ;
default :
break ;
}
}
* d + + = * s + + ;
} else {
size_t siz ;
/* Get the size of the next MB character. */
next_codepoint ( s , & siz ) ;
switch ( siz ) {
case 5 :
* d + + = * s + + ;
FALL_THROUGH ;
case 4 :
* d + + = * s + + ;
FALL_THROUGH ;
case 3 :
* d + + = * s + + ;
FALL_THROUGH ;
case 2 :
* d + + = * s + + ;
FALL_THROUGH ;
case 1 :
* d + + = * s + + ;
break ;
default :
DEBUG ( 0 , ( " check_path_syntax_internal: character length assumptions invalid ! \n " ) ) ;
* d = ' \0 ' ;
return NT_STATUS_INVALID_PARAMETER ;
}
}
start_of_name_component = False ;
}
* d = ' \0 ' ;
return ret ;
}
/****************************************************************************
Ensure we check the path in * exactly * the same way as W2K for regular pathnames .
No wildcards allowed .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS check_path_syntax ( char * path )
{
return check_path_syntax_internal ( path , false ) ;
}
/****************************************************************************
Check the path for a POSIX client .
We ' re assuming here that ' / ' is not the second byte in any multibyte char
set ( a safe assumption ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS check_path_syntax_posix ( char * path )
{
return check_path_syntax_internal ( path , true ) ;
}
2022-03-16 01:32:34 +03:00
/****************************************************************************
Pull a string and check the path allowing a wildcard - provide for error return .
Passes in posix flag .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static size_t srvstr_get_path_internal ( TALLOC_CTX * ctx ,
const char * base_ptr ,
uint16_t smb_flags2 ,
char * * pp_dest ,
const char * src ,
size_t src_len ,
int flags ,
bool posix_pathnames ,
NTSTATUS * err )
{
size_t ret ;
* pp_dest = NULL ;
ret = srvstr_pull_talloc ( ctx , base_ptr , smb_flags2 , pp_dest , src ,
src_len , flags ) ;
if ( ! * pp_dest ) {
* err = NT_STATUS_INVALID_PARAMETER ;
return ret ;
}
if ( smb_flags2 & FLAGS2_DFS_PATHNAMES ) {
/*
* For a DFS path the function parse_dfs_path ( )
* will do the path processing , just make a copy .
*/
* err = NT_STATUS_OK ;
return ret ;
}
if ( posix_pathnames ) {
* err = check_path_syntax_posix ( * pp_dest ) ;
} else {
* err = check_path_syntax ( * pp_dest ) ;
}
return ret ;
}
/****************************************************************************
Pull a string and check the path - provide for error return .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
size_t srvstr_get_path ( TALLOC_CTX * ctx ,
const char * base_ptr ,
uint16_t smb_flags2 ,
char * * pp_dest ,
const char * src ,
size_t src_len ,
int flags ,
NTSTATUS * err )
{
return srvstr_get_path_internal ( ctx ,
base_ptr ,
smb_flags2 ,
pp_dest ,
src ,
src_len ,
flags ,
false ,
err ) ;
}
/****************************************************************************
Pull a string and check the path - provide for error return .
posix_pathnames version .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
size_t srvstr_get_path_posix ( TALLOC_CTX * ctx ,
const char * base_ptr ,
uint16_t smb_flags2 ,
char * * pp_dest ,
const char * src ,
size_t src_len ,
int flags ,
NTSTATUS * err )
{
return srvstr_get_path_internal ( ctx ,
base_ptr ,
smb_flags2 ,
pp_dest ,
src ,
src_len ,
flags ,
true ,
err ) ;
}
size_t srvstr_get_path_req ( TALLOC_CTX * mem_ctx , struct smb_request * req ,
char * * pp_dest , const char * src , int flags ,
NTSTATUS * err )
{
ssize_t bufrem = smbreq_bufrem ( req , src ) ;
if ( bufrem < 0 ) {
* err = NT_STATUS_INVALID_PARAMETER ;
return 0 ;
}
if ( req - > posix_pathnames ) {
return srvstr_get_path_internal ( mem_ctx ,
( const char * ) req - > inbuf ,
req - > flags2 ,
pp_dest ,
src ,
bufrem ,
flags ,
true ,
err ) ;
} else {
return srvstr_get_path_internal ( mem_ctx ,
( const char * ) req - > inbuf ,
req - > flags2 ,
pp_dest ,
src ,
bufrem ,
flags ,
false ,
err ) ;
}
}
2022-03-17 19:45:00 +03:00
/**
* pull a string from the smb_buf part of a packet . In this case the
* string can either be null terminated or it can be terminated by the
* end of the smbbuf area
*/
size_t srvstr_pull_req_talloc ( TALLOC_CTX * ctx , struct smb_request * req ,
char * * dest , const uint8_t * src , int flags )
{
ssize_t bufrem = smbreq_bufrem ( req , src ) ;
if ( bufrem < 0 ) {
return 0 ;
}
return pull_string_talloc ( ctx , req - > inbuf , req - > flags2 , dest , src ,
bufrem , flags ) ;
}
2022-03-17 19:51:59 +03:00
/****************************************************************************
Check if we have a correct fsp pointing to a file . Basic check for open fsp .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool check_fsp_open ( connection_struct * conn , struct smb_request * req ,
files_struct * fsp )
{
if ( ( fsp = = NULL ) | | ( conn = = NULL ) ) {
reply_nterror ( req , NT_STATUS_INVALID_HANDLE ) ;
return False ;
}
if ( ( conn ! = fsp - > conn ) | | ( req - > vuid ! = fsp - > vuid ) ) {
reply_nterror ( req , NT_STATUS_INVALID_HANDLE ) ;
return False ;
}
return True ;
}
2022-03-17 19:53:35 +03:00
/****************************************************************************
Check if we have a correct fsp pointing to a file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool check_fsp ( connection_struct * conn , struct smb_request * req ,
files_struct * fsp )
{
if ( ! check_fsp_open ( conn , req , fsp ) ) {
return False ;
}
if ( fsp - > fsp_flags . is_directory ) {
reply_nterror ( req , NT_STATUS_INVALID_DEVICE_REQUEST ) ;
return False ;
}
if ( fsp_get_pathref_fd ( fsp ) = = - 1 ) {
reply_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return False ;
}
fsp - > num_smb_operations + + ;
return True ;
}
2022-03-17 19:57:04 +03:00
/****************************************************************************
Check if we have a correct fsp pointing to a quota fake file . Replacement for
the CHECK_NTQUOTA_HANDLE_OK macro .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool check_fsp_ntquota_handle ( connection_struct * conn , struct smb_request * req ,
files_struct * fsp )
{
if ( ! check_fsp_open ( conn , req , fsp ) ) {
return false ;
}
if ( fsp - > fsp_flags . is_directory ) {
return false ;
}
if ( fsp - > fake_file_handle = = NULL ) {
return false ;
}
if ( fsp - > fake_file_handle - > type ! = FAKE_FILE_TYPE_QUOTA ) {
return false ;
}
if ( fsp - > fake_file_handle - > private_data = = NULL ) {
return false ;
}
return true ;
}
2022-03-17 20:04:28 +03:00
/****************************************************************************
Return the port number we ' ve bound to on a socket .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int get_socket_port ( int fd )
{
struct samba_sockaddr saddr = {
. sa_socklen = sizeof ( struct sockaddr_storage ) ,
} ;
if ( fd = = - 1 ) {
return - 1 ;
}
if ( getsockname ( fd , & saddr . u . sa , & saddr . sa_socklen ) < 0 ) {
int level = ( errno = = ENOTCONN ) ? 2 : 0 ;
DEBUG ( level , ( " getsockname failed. Error was %s \n " ,
strerror ( errno ) ) ) ;
return - 1 ;
}
# if defined(HAVE_IPV6)
if ( saddr . u . sa . sa_family = = AF_INET6 ) {
return ntohs ( saddr . u . in6 . sin6_port ) ;
}
# endif
if ( saddr . u . sa . sa_family = = AF_INET ) {
return ntohs ( saddr . u . in . sin_port ) ;
}
return - 1 ;
}
static bool netbios_session_retarget ( struct smbXsrv_connection * xconn ,
const char * name , int name_type )
{
char * trim_name ;
char * trim_name_type ;
const char * retarget_parm ;
char * retarget ;
char * p ;
int retarget_type = 0x20 ;
int retarget_port = NBT_SMB_PORT ;
struct sockaddr_storage retarget_addr ;
struct sockaddr_in * in_addr ;
bool ret = false ;
uint8_t outbuf [ 10 ] ;
if ( get_socket_port ( xconn - > transport . sock ) ! = NBT_SMB_PORT ) {
return false ;
}
trim_name = talloc_strdup ( talloc_tos ( ) , name ) ;
if ( trim_name = = NULL ) {
goto fail ;
}
trim_char ( trim_name , ' ' , ' ' ) ;
trim_name_type = talloc_asprintf ( trim_name , " %s#%2.2x " , trim_name ,
name_type ) ;
if ( trim_name_type = = NULL ) {
goto fail ;
}
retarget_parm = lp_parm_const_string ( - 1 , " netbios retarget " ,
trim_name_type , NULL ) ;
if ( retarget_parm = = NULL ) {
retarget_parm = lp_parm_const_string ( - 1 , " netbios retarget " ,
trim_name , NULL ) ;
}
if ( retarget_parm = = NULL ) {
goto fail ;
}
retarget = talloc_strdup ( trim_name , retarget_parm ) ;
if ( retarget = = NULL ) {
goto fail ;
}
DEBUG ( 10 , ( " retargeting %s to %s \n " , trim_name_type , retarget ) ) ;
p = strchr ( retarget , ' : ' ) ;
if ( p ! = NULL ) {
* p + + = ' \0 ' ;
retarget_port = atoi ( p ) ;
}
p = strchr_m ( retarget , ' # ' ) ;
if ( p ! = NULL ) {
* p + + = ' \0 ' ;
if ( sscanf ( p , " %x " , & retarget_type ) ! = 1 ) {
goto fail ;
}
}
ret = resolve_name ( retarget , & retarget_addr , retarget_type , false ) ;
if ( ! ret ) {
DEBUG ( 10 , ( " could not resolve %s \n " , retarget ) ) ;
goto fail ;
}
if ( retarget_addr . ss_family ! = AF_INET ) {
DEBUG ( 10 , ( " Retarget target not an IPv4 addr \n " ) ) ;
goto fail ;
}
in_addr = ( struct sockaddr_in * ) ( void * ) & retarget_addr ;
_smb_setlen ( outbuf , 6 ) ;
SCVAL ( outbuf , 0 , 0x84 ) ;
* ( uint32_t * ) ( outbuf + 4 ) = in_addr - > sin_addr . s_addr ;
* ( uint16_t * ) ( outbuf + 8 ) = htons ( retarget_port ) ;
if ( ! srv_send_smb ( xconn , ( char * ) outbuf , false , 0 , false ,
NULL ) ) {
exit_server_cleanly ( " netbios_session_retarget: srv_send_smb "
" failed. " ) ;
}
ret = true ;
fail :
TALLOC_FREE ( trim_name ) ;
return ret ;
}
static void reply_called_name_not_present ( char * outbuf )
{
smb_setlen ( outbuf , 1 ) ;
SCVAL ( outbuf , 0 , 0x83 ) ;
SCVAL ( outbuf , 4 , 0x82 ) ;
}
/****************************************************************************
Reply to a ( netbios - level ) special message .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void reply_special ( struct smbXsrv_connection * xconn , char * inbuf , size_t inbuf_size )
{
struct smbd_server_connection * sconn = xconn - > client - > sconn ;
int msg_type = CVAL ( inbuf , 0 ) ;
int msg_flags = CVAL ( inbuf , 1 ) ;
/*
* We only really use 4 bytes of the outbuf , but for the smb_setlen
* calculation & friends ( srv_send_smb uses that ) we need the full smb
* header .
*/
char outbuf [ smb_size ] ;
memset ( outbuf , ' \0 ' , sizeof ( outbuf ) ) ;
smb_setlen ( outbuf , 0 ) ;
switch ( msg_type ) {
case NBSSrequest : /* session request */
{
/* inbuf_size is guarenteed to be at least 4. */
fstring name1 , name2 ;
int name_type1 , name_type2 ;
int name_len1 , name_len2 ;
* name1 = * name2 = 0 ;
if ( xconn - > transport . nbt . got_session ) {
exit_server_cleanly ( " multiple session request not permitted " ) ;
}
SCVAL ( outbuf , 0 , NBSSpositive ) ;
SCVAL ( outbuf , 3 , 0 ) ;
/* inbuf_size is guaranteed to be at least 4. */
name_len1 = name_len ( ( unsigned char * ) ( inbuf + 4 ) , inbuf_size - 4 ) ;
if ( name_len1 < = 0 | | name_len1 > inbuf_size - 4 ) {
DEBUG ( 0 , ( " Invalid name length in session request \n " ) ) ;
reply_called_name_not_present ( outbuf ) ;
break ;
}
name_len2 = name_len ( ( unsigned char * ) ( inbuf + 4 + name_len1 ) , inbuf_size - 4 - name_len1 ) ;
if ( name_len2 < = 0 | | name_len2 > inbuf_size - 4 - name_len1 ) {
DEBUG ( 0 , ( " Invalid name length in session request \n " ) ) ;
reply_called_name_not_present ( outbuf ) ;
break ;
}
name_type1 = name_extract ( ( unsigned char * ) inbuf ,
inbuf_size , ( unsigned int ) 4 , name1 ) ;
name_type2 = name_extract ( ( unsigned char * ) inbuf ,
inbuf_size , ( unsigned int ) ( 4 + name_len1 ) , name2 ) ;
if ( name_type1 = = - 1 | | name_type2 = = - 1 ) {
DEBUG ( 0 , ( " Invalid name type in session request \n " ) ) ;
reply_called_name_not_present ( outbuf ) ;
break ;
}
DEBUG ( 2 , ( " netbios connect: name1=%s0x%x name2=%s0x%x \n " ,
name1 , name_type1 , name2 , name_type2 ) ) ;
if ( netbios_session_retarget ( xconn , name1 , name_type1 ) ) {
exit_server_cleanly ( " retargeted client " ) ;
}
/*
* Windows NT / 2 k uses " *SMBSERVER " and XP uses
* " *SMBSERV " arrggg ! ! !
*/
if ( strequal ( name1 , " *SMBSERVER " )
| | strequal ( name1 , " *SMBSERV " ) ) {
char * raddr ;
raddr = tsocket_address_inet_addr_string ( sconn - > remote_address ,
talloc_tos ( ) ) ;
if ( raddr = = NULL ) {
exit_server_cleanly ( " could not allocate raddr " ) ;
}
fstrcpy ( name1 , raddr ) ;
}
set_local_machine_name ( name1 , True ) ;
set_remote_machine_name ( name2 , True ) ;
if ( is_ipaddress ( sconn - > remote_hostname ) ) {
char * p = discard_const_p ( char , sconn - > remote_hostname ) ;
talloc_free ( p ) ;
sconn - > remote_hostname = talloc_strdup ( sconn ,
get_remote_machine_name ( ) ) ;
if ( sconn - > remote_hostname = = NULL ) {
exit_server_cleanly ( " could not copy remote name " ) ;
}
xconn - > remote_hostname = sconn - > remote_hostname ;
}
DEBUG ( 2 , ( " netbios connect: local=%s remote=%s, name type = %x \n " ,
get_local_machine_name ( ) , get_remote_machine_name ( ) ,
name_type2 ) ) ;
if ( name_type2 = = ' R ' ) {
/* We are being asked for a pathworks session ---
no thanks ! */
reply_called_name_not_present ( outbuf ) ;
break ;
}
reload_services ( sconn , conn_snum_used , true ) ;
reopen_logs ( ) ;
xconn - > transport . nbt . got_session = true ;
break ;
}
case 0x89 : /* session keepalive request
( some old clients produce this ? ) */
SCVAL ( outbuf , 0 , NBSSkeepalive ) ;
SCVAL ( outbuf , 3 , 0 ) ;
break ;
case NBSSpositive : /* positive session response */
case NBSSnegative : /* negative session response */
case NBSSretarget : /* retarget session response */
DEBUG ( 0 , ( " Unexpected session response \n " ) ) ;
break ;
case NBSSkeepalive : /* session keepalive */
default :
return ;
}
DEBUG ( 5 , ( " init msg_type=0x%x msg_flags=0x%x \n " ,
msg_type , msg_flags ) ) ;
if ( ! srv_send_smb ( xconn , outbuf , false , 0 , false , NULL ) ) {
exit_server_cleanly ( " reply_special: srv_send_smb failed. " ) ;
}
if ( CVAL ( outbuf , 0 ) ! = 0x82 ) {
exit_server_cleanly ( " invalid netbios session " ) ;
}
return ;
}
2022-03-17 20:10:51 +03:00
/*******************************************************************
* unlink a file with all relevant access checks
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS unlink_internals ( connection_struct * conn ,
struct smb_request * req ,
uint32_t dirtype ,
struct smb_filename * smb_fname )
{
uint32_t fattr ;
files_struct * fsp ;
uint32_t dirtype_orig = dirtype ;
NTSTATUS status ;
int ret ;
struct smb2_create_blobs * posx = NULL ;
if ( dirtype = = 0 ) {
dirtype = FILE_ATTRIBUTE_NORMAL ;
}
DBG_DEBUG ( " %s, dirtype = %d \n " ,
smb_fname_str_dbg ( smb_fname ) ,
dirtype ) ;
if ( ! CAN_WRITE ( conn ) ) {
return NT_STATUS_MEDIA_WRITE_PROTECTED ;
}
ret = vfs_stat ( conn , smb_fname ) ;
if ( ret ! = 0 ) {
return map_nt_error_from_unix ( errno ) ;
}
fattr = fdos_mode ( smb_fname - > fsp ) ;
if ( dirtype & FILE_ATTRIBUTE_NORMAL ) {
dirtype = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY ;
}
dirtype & = ( FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM ) ;
if ( ! dirtype ) {
return NT_STATUS_NO_SUCH_FILE ;
}
if ( ! dir_check_ftype ( fattr , dirtype ) ) {
if ( fattr & FILE_ATTRIBUTE_DIRECTORY ) {
return NT_STATUS_FILE_IS_A_DIRECTORY ;
}
return NT_STATUS_NO_SUCH_FILE ;
}
if ( dirtype_orig & 0x8000 ) {
/* These will never be set for POSIX. */
return NT_STATUS_NO_SUCH_FILE ;
}
#if 0
if ( ( fattr & dirtype ) & FILE_ATTRIBUTE_DIRECTORY ) {
return NT_STATUS_FILE_IS_A_DIRECTORY ;
}
if ( ( fattr & ~ dirtype ) & ( FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM ) ) {
return NT_STATUS_NO_SUCH_FILE ;
}
if ( dirtype & 0xFF00 ) {
/* These will never be set for POSIX. */
return NT_STATUS_NO_SUCH_FILE ;
}
dirtype & = 0xFF ;
if ( ! dirtype ) {
return NT_STATUS_NO_SUCH_FILE ;
}
/* Can't delete a directory. */
if ( fattr & FILE_ATTRIBUTE_DIRECTORY ) {
return NT_STATUS_FILE_IS_A_DIRECTORY ;
}
# endif
#if 0 /* JRATEST */
else if ( dirtype & FILE_ATTRIBUTE_DIRECTORY ) /* Asked for a directory and it isn't. */
return NT_STATUS_OBJECT_NAME_INVALID ;
# endif /* JRATEST */
if ( smb_fname - > flags & SMB_FILENAME_POSIX_PATH ) {
status = make_smb2_posix_create_ctx (
talloc_tos ( ) , & posx , 0777 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_WARNING ( " make_smb2_posix_create_ctx failed: %s \n " ,
nt_errstr ( status ) ) ;
return status ;
}
}
/* On open checks the open itself will check the share mode, so
don ' t do it here as we ' ll get it wrong . */
status = SMB_VFS_CREATE_FILE
( conn , /* conn */
req , /* req */
smb_fname , /* fname */
DELETE_ACCESS , /* access_mask */
FILE_SHARE_NONE , /* share_access */
FILE_OPEN , /* create_disposition*/
FILE_NON_DIRECTORY_FILE , /* create_options */
FILE_ATTRIBUTE_NORMAL , /* file_attributes */
0 , /* oplock_request */
NULL , /* lease */
0 , /* allocation_size */
0 , /* private_flags */
NULL , /* sd */
NULL , /* ea_list */
& fsp , /* result */
NULL , /* pinfo */
posx , /* in_context_blobs */
NULL ) ; /* out_context_blobs */
TALLOC_FREE ( posx ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " SMB_VFS_CREATEFILE failed: %s \n " ,
nt_errstr ( status ) ) ;
return status ;
}
status = can_set_delete_on_close ( fsp , fattr ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DBG_DEBUG ( " can_set_delete_on_close for file %s - "
" (%s) \n " ,
smb_fname_str_dbg ( smb_fname ) ,
nt_errstr ( status ) ) ;
close_file_free ( req , & fsp , NORMAL_CLOSE ) ;
return status ;
}
/* The set is across all open files on this dev/inode pair. */
if ( ! set_delete_on_close ( fsp , True ,
conn - > session_info - > security_token ,
conn - > session_info - > unix_token ) ) {
close_file_free ( req , & fsp , NORMAL_CLOSE ) ;
return NT_STATUS_ACCESS_DENIED ;
}
return close_file_free ( req , & fsp , NORMAL_CLOSE ) ;
}
2022-03-17 20:15:23 +03:00
/****************************************************************************
Fake ( read / write ) sendfile . Returns - 1 on read or write fail .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
ssize_t fake_sendfile ( struct smbXsrv_connection * xconn , files_struct * fsp ,
off_t startpos , size_t nread )
{
size_t bufsize ;
size_t tosend = nread ;
char * buf ;
if ( nread = = 0 ) {
return 0 ;
}
bufsize = MIN ( nread , 65536 ) ;
if ( ! ( buf = SMB_MALLOC_ARRAY ( char , bufsize ) ) ) {
return - 1 ;
}
while ( tosend > 0 ) {
ssize_t ret ;
size_t cur_read ;
cur_read = MIN ( tosend , bufsize ) ;
ret = read_file ( fsp , buf , startpos , cur_read ) ;
if ( ret = = - 1 ) {
SAFE_FREE ( buf ) ;
return - 1 ;
}
/* If we had a short read, fill with zeros. */
if ( ret < cur_read ) {
memset ( buf + ret , ' \0 ' , cur_read - ret ) ;
}
ret = write_data ( xconn - > transport . sock , buf , cur_read ) ;
if ( ret ! = cur_read ) {
int saved_errno = errno ;
/*
* Try and give an error message saying what
* client failed .
*/
DEBUG ( 0 , ( " write_data failed for client %s. "
" Error %s \n " ,
smbXsrv_connection_dbg ( xconn ) ,
strerror ( saved_errno ) ) ) ;
SAFE_FREE ( buf ) ;
errno = saved_errno ;
return - 1 ;
}
tosend - = cur_read ;
startpos + = cur_read ;
}
SAFE_FREE ( buf ) ;
return ( ssize_t ) nread ;
}