2022-03-15 23:50:16 +03:00
/*
Unix SMB / CIFS implementation .
Pipe SMB reply routines
Copyright ( C ) Andrew Tridgell 1992 - 1998
Copyright ( C ) Luke Kenneth Casson Leighton 1996 - 1998
Copyright ( C ) Paul Ashton 1997 - 1998.
Copyright ( C ) Jeremy Allison 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/>.
*/
/*
This file handles reply_ calls on named pipes that the server
makes to handle specific protocols
*/
# include "includes.h"
# include "smbd/smbd.h"
# include "smbd/globals.h"
# include "libcli/security/security.h"
# include "rpc_server/srv_pipe_hnd.h"
# include "auth/auth_util.h"
# include "librpc/rpc/dcerpc_helper.h"
/****************************************************************************
Reply to an open and X on a named pipe .
This code is basically stolen from reply_open_and_X with some
wrinkles to handle pipes .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void reply_open_pipe_and_X ( connection_struct * conn , struct smb_request * req )
{
const char * fname = NULL ;
char * pipe_name = NULL ;
files_struct * fsp ;
TALLOC_CTX * ctx = talloc_tos ( ) ;
NTSTATUS status ;
/* XXXX we need to handle passed times, sattr and flags */
srvstr_pull_req_talloc ( ctx , req , & pipe_name , req - > buf , STR_TERMINATE ) ;
if ( ! pipe_name ) {
reply_botherror ( req , NT_STATUS_OBJECT_NAME_NOT_FOUND ,
ERRDOS , ERRbadpipe ) ;
return ;
}
/* If the name doesn't start \PIPE\ then this is directed */
/* at a mailslot or something we really, really don't understand, */
/* not just something we really don't understand. */
# define PIPE "PIPE\\"
# define PIPELEN strlen(PIPE)
fname = pipe_name ;
while ( fname [ 0 ] = = ' \\ ' ) {
fname + + ;
}
if ( ! strnequal ( fname , PIPE , PIPELEN ) ) {
reply_nterror ( req , NT_STATUS_OBJECT_PATH_SYNTAX_BAD ) ;
return ;
}
fname + = PIPELEN ;
while ( fname [ 0 ] = = ' \\ ' ) {
fname + + ;
}
DEBUG ( 4 , ( " Opening pipe %s => %s. \n " , pipe_name , fname ) ) ;
status = open_np_file ( req , fname , & fsp ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
if ( NT_STATUS_EQUAL ( status , NT_STATUS_OBJECT_NAME_NOT_FOUND ) ) {
reply_botherror ( req , NT_STATUS_OBJECT_NAME_NOT_FOUND ,
ERRDOS , ERRbadpipe ) ;
return ;
}
reply_nterror ( req , status ) ;
return ;
}
/* Prepare the reply */
2022-04-05 05:53:20 +03:00
reply_smb1_outbuf ( req , 15 , 0 ) ;
2022-03-15 23:50:16 +03:00
SSVAL ( req - > outbuf , smb_vwv0 , 0xff ) ; /* andx chain ends */
SSVAL ( req - > outbuf , smb_vwv1 , 0 ) ; /* no andx offset */
/* Mark the opened file as an existing named pipe in message mode. */
SSVAL ( req - > outbuf , smb_vwv9 , 2 ) ;
SSVAL ( req - > outbuf , smb_vwv10 , 0xc700 ) ;
SSVAL ( req - > outbuf , smb_vwv2 , fsp - > fnum ) ;
SSVAL ( req - > outbuf , smb_vwv3 , 0 ) ; /* fmode */
srv_put_dos_date3 ( ( char * ) req - > outbuf , smb_vwv4 , 0 ) ; /* mtime */
SIVAL ( req - > outbuf , smb_vwv6 , 0 ) ; /* size */
SSVAL ( req - > outbuf , smb_vwv8 , 0 ) ; /* rmode */
SSVAL ( req - > outbuf , smb_vwv11 , 0x0001 ) ;
}
2022-03-15 23:55:38 +03:00
/****************************************************************************
Reply to a write and X .
This code is basically stolen from reply_write_and_X with some
wrinkles to handle pipes .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct pipe_write_andx_state {
bool pipe_start_message_raw ;
size_t numtowrite ;
} ;
static void pipe_write_andx_done ( struct tevent_req * subreq ) ;
void reply_pipe_write_and_X ( struct smb_request * req )
{
files_struct * fsp = file_fsp ( req , SVAL ( req - > vwv + 2 , 0 ) ) ;
int smb_doff = SVAL ( req - > vwv + 11 , 0 ) ;
const uint8_t * data ;
struct pipe_write_andx_state * state ;
struct tevent_req * subreq ;
if ( ! fsp_is_np ( fsp ) ) {
reply_nterror ( req , NT_STATUS_INVALID_HANDLE ) ;
return ;
}
if ( fsp - > vuid ! = req - > vuid ) {
reply_nterror ( req , NT_STATUS_INVALID_HANDLE ) ;
return ;
}
state = talloc ( req , struct pipe_write_andx_state ) ;
if ( state = = NULL ) {
reply_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
req - > async_priv = state ;
state - > numtowrite = SVAL ( req - > vwv + 10 , 0 ) ;
state - > pipe_start_message_raw =
( ( SVAL ( req - > vwv + 7 , 0 ) & ( PIPE_START_MESSAGE | PIPE_RAW_MODE ) )
= = ( PIPE_START_MESSAGE | PIPE_RAW_MODE ) ) ;
DEBUG ( 6 , ( " reply_pipe_write_and_X: %s, name: %s len: %d \n " ,
fsp_fnum_dbg ( fsp ) , fsp_str_dbg ( fsp ) , ( int ) state - > numtowrite ) ) ;
data = ( const uint8_t * ) smb_base ( req - > inbuf ) + smb_doff ;
if ( state - > pipe_start_message_raw ) {
/*
* For the start of a message in named pipe byte mode ,
* the first two bytes are a length - of - pdu field . Ignore
* them ( we don ' t trust the client ) . JRA .
*/
if ( state - > numtowrite < 2 ) {
DEBUG ( 0 , ( " reply_pipe_write_and_X: start of message "
" set and not enough data sent.(%u) \n " ,
( unsigned int ) state - > numtowrite ) ) ;
reply_nterror ( req , NT_STATUS_INVALID_PARAMETER ) ;
return ;
}
data + = 2 ;
state - > numtowrite - = 2 ;
}
subreq = np_write_send ( state , req - > sconn - > ev_ctx ,
fsp - > fake_file_handle , data , state - > numtowrite ) ;
if ( subreq = = NULL ) {
TALLOC_FREE ( state ) ;
reply_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
tevent_req_set_callback ( subreq , pipe_write_andx_done ,
talloc_move ( req - > conn , & req ) ) ;
}
static void pipe_write_andx_done ( struct tevent_req * subreq )
{
struct smb_request * req = tevent_req_callback_data (
subreq , struct smb_request ) ;
struct pipe_write_andx_state * state = talloc_get_type_abort (
req - > async_priv , struct pipe_write_andx_state ) ;
NTSTATUS status ;
ssize_t nwritten = - 1 ;
status = np_write_recv ( subreq , & nwritten ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
reply_nterror ( req , status ) ;
goto done ;
}
/* Looks bogus to me now. Is this error message correct ? JRA. */
if ( nwritten ! = state - > numtowrite ) {
reply_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
goto done ;
}
2022-04-05 05:53:20 +03:00
reply_smb1_outbuf ( req , 6 , 0 ) ;
2022-03-15 23:55:38 +03:00
SSVAL ( req - > outbuf , smb_vwv0 , 0xff ) ; /* andx chain ends */
SSVAL ( req - > outbuf , smb_vwv1 , 0 ) ; /* no andx offset */
nwritten = ( state - > pipe_start_message_raw ? nwritten + 2 : nwritten ) ;
SSVAL ( req - > outbuf , smb_vwv2 , nwritten ) ;
DEBUG ( 3 , ( " writeX-IPC nwritten=%d \n " , ( int ) nwritten ) ) ;
done :
/*
* We must free here as the ownership of req was
* moved to the connection struct in reply_pipe_write_and_X ( ) .
*/
smb_request_done ( req ) ;
}
2022-03-16 00:00:05 +03:00
/****************************************************************************
Reply to a read and X .
This code is basically stolen from reply_read_and_X with some
wrinkles to handle pipes .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct pipe_read_andx_state {
uint8_t * outbuf ;
int smb_mincnt ;
int smb_maxcnt ;
} ;
static void pipe_read_andx_done ( struct tevent_req * subreq ) ;
void reply_pipe_read_and_X ( struct smb_request * req )
{
files_struct * fsp = file_fsp ( req , SVAL ( req - > vwv + 0 , 0 ) ) ;
uint8_t * data ;
struct pipe_read_andx_state * state ;
struct tevent_req * subreq ;
/* we don't use the offset given to use for pipe reads. This
is deliberate , instead we always return the next lump of
data on the pipe */
#if 0
uint32_t smb_offs = IVAL ( req - > vwv + 3 , 0 ) ;
# endif
if ( ! fsp_is_np ( fsp ) ) {
reply_nterror ( req , NT_STATUS_INVALID_HANDLE ) ;
return ;
}
if ( fsp - > vuid ! = req - > vuid ) {
reply_nterror ( req , NT_STATUS_INVALID_HANDLE ) ;
return ;
}
state = talloc ( req , struct pipe_read_andx_state ) ;
if ( state = = NULL ) {
reply_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
req - > async_priv = state ;
state - > smb_maxcnt = SVAL ( req - > vwv + 5 , 0 ) ;
state - > smb_mincnt = SVAL ( req - > vwv + 6 , 0 ) ;
2022-04-05 05:53:20 +03:00
reply_smb1_outbuf ( req , 12 , state - > smb_maxcnt + 1 /* padding byte */ ) ;
2022-03-16 00:00:05 +03:00
SSVAL ( req - > outbuf , smb_vwv0 , 0xff ) ; /* andx chain ends */
SSVAL ( req - > outbuf , smb_vwv1 , 0 ) ; /* no andx offset */
SCVAL ( smb_buf ( req - > outbuf ) , 0 , 0 ) ; /* padding byte */
data = ( uint8_t * ) smb_buf ( req - > outbuf ) + 1 /* padding byte */ ;
/*
* We have to tell the upper layers that we ' re async .
*/
state - > outbuf = req - > outbuf ;
req - > outbuf = NULL ;
subreq = np_read_send ( state , req - > sconn - > ev_ctx ,
fsp - > fake_file_handle , data ,
state - > smb_maxcnt ) ;
if ( subreq = = NULL ) {
reply_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
tevent_req_set_callback ( subreq , pipe_read_andx_done ,
talloc_move ( req - > conn , & req ) ) ;
}
static void pipe_read_andx_done ( struct tevent_req * subreq )
{
struct smb_request * req = tevent_req_callback_data (
subreq , struct smb_request ) ;
struct pipe_read_andx_state * state = talloc_get_type_abort (
req - > async_priv , struct pipe_read_andx_state ) ;
NTSTATUS status ;
ssize_t nread ;
bool is_data_outstanding ;
status = np_read_recv ( subreq , & nread , & is_data_outstanding ) ;
TALLOC_FREE ( subreq ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
NTSTATUS old = status ;
status = nt_status_np_pipe ( old ) ;
reply_nterror ( req , status ) ;
goto done ;
}
req - > outbuf = state - > outbuf ;
state - > outbuf = NULL ;
2022-04-05 04:40:11 +03:00
srv_smb1_set_message ( ( char * ) req - > outbuf , 12 , nread + 1 /* padding byte */ ,
2022-03-16 00:00:05 +03:00
false ) ;
#if 0
/*
* we should return STATUS_BUFFER_OVERFLOW if there ' s
* out standing data .
*
* But we can ' t enable it yet , as it has bad interactions
* with fixup_chain_error_packet ( ) in chain_reply ( ) .
*/
if ( is_data_outstanding ) {
error_packet_set ( ( char * ) req - > outbuf , ERRDOS , ERRmoredata ,
STATUS_BUFFER_OVERFLOW , __LINE__ , __FILE__ ) ;
}
# endif
SSVAL ( req - > outbuf , smb_vwv5 , nread ) ;
SSVAL ( req - > outbuf , smb_vwv6 ,
( smb_wct - 4 ) /* offset from smb header to wct */
+ 1 /* the wct field */
+ 12 * sizeof ( uint16_t ) /* vwv */
+ 2 /* the buflen field */
+ 1 ) ; /* padding byte */
DEBUG ( 3 , ( " readX-IPC min=%d max=%d nread=%d \n " ,
state - > smb_mincnt , state - > smb_maxcnt , ( int ) nread ) ) ;
done :
/*
* We must free here as the ownership of req was
* moved to the connection struct in reply_pipe_read_and_X ( ) .
*/
smb_request_done ( req ) ;
}
2022-03-31 20:37:25 +03:00
/****************************************************************************
Reply to a write on a pipe .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct pipe_write_state {
size_t numtowrite ;
} ;
static void pipe_write_done ( struct tevent_req * subreq ) ;
void reply_pipe_write ( struct smb_request * req )
{
files_struct * fsp = file_fsp ( req , SVAL ( req - > vwv + 0 , 0 ) ) ;
const uint8_t * data ;
struct pipe_write_state * state ;
struct tevent_req * subreq ;
if ( ! fsp_is_np ( fsp ) ) {
reply_nterror ( req , NT_STATUS_INVALID_HANDLE ) ;
return ;
}
if ( fsp - > vuid ! = req - > vuid ) {
reply_nterror ( req , NT_STATUS_INVALID_HANDLE ) ;
return ;
}
state = talloc ( req , struct pipe_write_state ) ;
if ( state = = NULL ) {
reply_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
req - > async_priv = state ;
state - > numtowrite = SVAL ( req - > vwv + 1 , 0 ) ;
data = req - > buf + 3 ;
DEBUG ( 6 , ( " reply_pipe_write: %s, name: %s len: %d \n " , fsp_fnum_dbg ( fsp ) ,
fsp_str_dbg ( fsp ) , ( int ) state - > numtowrite ) ) ;
subreq = np_write_send ( state , req - > sconn - > ev_ctx ,
fsp - > fake_file_handle , data , state - > numtowrite ) ;
if ( subreq = = NULL ) {
TALLOC_FREE ( state ) ;
reply_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return ;
}
tevent_req_set_callback ( subreq , pipe_write_done ,
talloc_move ( req - > conn , & req ) ) ;
}
static void pipe_write_done ( struct tevent_req * subreq )
{
struct smb_request * req = tevent_req_callback_data (
subreq , struct smb_request ) ;
struct pipe_write_state * state = talloc_get_type_abort (
req - > async_priv , struct pipe_write_state ) ;
NTSTATUS status ;
ssize_t nwritten = - 1 ;
status = np_write_recv ( subreq , & nwritten ) ;
TALLOC_FREE ( subreq ) ;
if ( nwritten < 0 ) {
reply_nterror ( req , status ) ;
goto send ;
}
/* Looks bogus to me now. Needs to be removed ? JRA. */
if ( ( nwritten = = 0 & & state - > numtowrite ! = 0 ) ) {
reply_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
goto send ;
}
2022-04-05 05:53:20 +03:00
reply_smb1_outbuf ( req , 1 , 0 ) ;
2022-03-31 20:37:25 +03:00
SSVAL ( req - > outbuf , smb_vwv0 , nwritten ) ;
DEBUG ( 3 , ( " write-IPC nwritten=%d \n " , ( int ) nwritten ) ) ;
send :
2023-06-05 16:45:35 +03:00
if ( ! smb1_srv_send ( req - > xconn ,
( char * ) req - > outbuf ,
true ,
req - > seqnum + 1 ,
IS_CONN_ENCRYPTED ( req - > conn ) | | req - > encrypted ) ) {
exit_server_cleanly ( " construct_reply: smb1_srv_send failed. " ) ;
}
2022-03-31 20:37:25 +03:00
TALLOC_FREE ( req ) ;
}