2003-08-13 01:53:07 +00:00
/*
Unix SMB / CIFS implementation .
SMB client transport context management functions
2005-01-16 11:15:08 +00:00
Copyright ( C ) Andrew Tridgell 1994 - 2005
2003-08-13 01:53:07 +00:00
Copyright ( C ) James Myers 2003 < myersjj @ samba . org >
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 02:07:03 +00:00
the Free Software Foundation ; either version 3 of the License , or
2003-08-13 01:53:07 +00: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 02:07:03 +00:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
2003-08-13 01:53:07 +00:00
*/
# include "includes.h"
2004-11-01 01:03:22 +00:00
# include "libcli/raw/libcliraw.h"
2008-04-02 04:53:27 +02:00
# include "libcli/raw/raw_proto.h"
2005-02-10 06:59:29 +00:00
# include "lib/socket/socket.h"
2008-10-11 21:31:42 +02:00
# include "../lib/util/dlinklist.h"
2005-02-03 11:56:03 +00:00
# include "lib/events/events.h"
2005-11-09 08:13:41 +00:00
# include "lib/stream/packet.h"
2006-03-16 00:23:11 +00:00
# include "librpc/gen_ndr/ndr_nbt.h"
2008-09-23 08:06:33 +02:00
# include "../libcli/nbt/libnbt.h"
2003-08-13 01:53:07 +00:00
2004-09-25 11:18:04 +00:00
2004-07-23 06:40:49 +00:00
/*
an event has happened on the socket
*/
2008-12-29 20:24:57 +01:00
static void smbcli_transport_event_handler ( struct tevent_context * ev ,
struct tevent_fd * fde ,
2009-02-02 08:24:59 +01:00
uint16_t flags , void * private_data )
2004-07-23 06:40:49 +00:00
{
2009-02-02 08:24:59 +01:00
struct smbcli_transport * transport = talloc_get_type ( private_data ,
2005-02-03 02:35:52 +00:00
struct smbcli_transport ) ;
2010-05-25 15:26:42 -04:00
if ( flags & TEVENT_FD_READ ) {
2005-11-09 08:13:41 +00:00
packet_recv ( transport - > packet ) ;
2005-01-21 06:55:33 +00:00
return ;
2004-09-25 11:18:04 +00:00
}
2010-05-25 15:26:42 -04:00
if ( flags & TEVENT_FD_WRITE ) {
2005-11-09 13:34:36 +00:00
packet_queue_run ( transport - > packet ) ;
2004-09-25 11:18:04 +00:00
}
2004-07-23 06:40:49 +00:00
}
2004-09-26 11:30:20 +00:00
/*
destroy a transport
*/
2006-05-24 07:34:11 +00:00
static int transport_destructor ( struct smbcli_transport * transport )
2004-09-26 11:30:20 +00:00
{
2006-07-13 17:37:45 +00:00
smbcli_transport_dead ( transport , NT_STATUS_LOCAL_DISCONNECT ) ;
2004-09-26 11:30:20 +00:00
return 0 ;
}
2005-11-09 08:13:41 +00:00
/*
handle receive errors
*/
2009-02-02 08:24:59 +01:00
static void smbcli_transport_error ( void * private_data , NTSTATUS status )
2005-11-09 08:13:41 +00:00
{
2009-02-02 08:24:59 +01:00
struct smbcli_transport * transport = talloc_get_type ( private_data , struct smbcli_transport ) ;
2006-07-13 17:37:45 +00:00
smbcli_transport_dead ( transport , status ) ;
2005-11-09 08:13:41 +00:00
}
2009-02-02 08:24:59 +01:00
static NTSTATUS smbcli_transport_finish_recv ( void * private_data , DATA_BLOB blob ) ;
2005-11-09 08:13:41 +00:00
2003-08-13 01:53:07 +00:00
/*
create a transport structure based on an established socket
*/
2005-01-24 00:57:14 +00:00
struct smbcli_transport * smbcli_transport_init ( struct smbcli_socket * sock ,
2007-10-06 22:28:14 +00:00
TALLOC_CTX * parent_ctx ,
2007-12-03 21:25:06 +01:00
bool primary ,
2010-05-09 17:20:01 +02:00
struct smbcli_options * options )
2003-08-13 01:53:07 +00:00
{
2004-08-04 13:23:35 +00:00
struct smbcli_transport * transport ;
2003-08-13 01:53:07 +00:00
2005-01-24 00:57:14 +00:00
transport = talloc_zero ( parent_ctx , struct smbcli_transport ) ;
2003-08-13 01:53:07 +00:00
if ( ! transport ) return NULL ;
2005-01-24 00:57:14 +00:00
if ( primary ) {
transport - > socket = talloc_steal ( transport , sock ) ;
} else {
transport - > socket = talloc_reference ( transport , sock ) ;
}
2003-08-13 01:53:07 +00:00
transport - > negotiate . protocol = PROTOCOL_NT1 ;
2008-01-03 17:22:12 -06:00
transport - > options = * options ;
2004-10-29 06:01:00 +00:00
transport - > negotiate . max_xmit = transport - > options . max_xmit ;
2005-11-09 08:13:41 +00:00
/* setup the stream -> packet parser */
transport - > packet = packet_init ( transport ) ;
if ( transport - > packet = = NULL ) {
talloc_free ( transport ) ;
return NULL ;
}
packet_set_private ( transport - > packet , transport ) ;
packet_set_socket ( transport - > packet , transport - > socket - > sock ) ;
packet_set_callback ( transport - > packet , smbcli_transport_finish_recv ) ;
packet_set_full_request ( transport - > packet , packet_full_request_nbt ) ;
packet_set_error_handler ( transport - > packet , smbcli_transport_error ) ;
packet_set_event_context ( transport - > packet , transport - > socket - > event . ctx ) ;
2005-11-10 11:10:40 +00:00
packet_set_nofree ( transport - > packet ) ;
2009-05-19 16:18:38 +02:00
packet_set_initial_read ( transport - > packet , 4 ) ;
2005-11-09 08:13:41 +00:00
2004-08-04 13:23:35 +00:00
smbcli_init_signing ( transport ) ;
2004-07-12 09:11:13 +00:00
2003-11-17 03:38:13 +00:00
ZERO_STRUCT ( transport - > called ) ;
2005-01-15 10:38:12 +00:00
/* take over event handling from the socket layer - it only
handles events up until we are connected */
2005-02-03 02:35:52 +00:00
talloc_free ( transport - > socket - > event . fde ) ;
2010-05-25 15:26:42 -04:00
transport - > socket - > event . fde = tevent_add_fd ( transport - > socket - > event . ctx ,
2005-12-01 00:22:08 +00:00
transport - > socket - > sock ,
2005-02-03 02:35:52 +00:00
socket_get_fd ( transport - > socket - > sock ) ,
2010-05-25 15:26:42 -04:00
TEVENT_FD_READ ,
2005-02-03 02:35:52 +00:00
smbcli_transport_event_handler ,
transport ) ;
2004-07-23 06:40:49 +00:00
2005-11-14 03:45:57 +00:00
packet_set_fde ( transport - > packet , transport - > socket - > event . fde ) ;
packet_set_serialise ( transport - > packet ) ;
2004-09-26 11:30:20 +00:00
talloc_set_destructor ( transport , transport_destructor ) ;
2003-08-13 01:53:07 +00:00
2004-09-26 11:30:20 +00:00
return transport ;
2003-08-13 01:53:07 +00:00
}
2004-04-23 04:21:22 +00:00
/*
mark the transport as dead
*/
2006-07-13 17:37:45 +00:00
void smbcli_transport_dead ( struct smbcli_transport * transport , NTSTATUS status )
2004-04-23 04:21:22 +00:00
{
2004-08-04 13:23:35 +00:00
smbcli_sock_dead ( transport - > socket ) ;
2004-08-03 08:04:11 +00:00
2006-07-13 17:37:45 +00:00
if ( NT_STATUS_EQUAL ( NT_STATUS_UNSUCCESSFUL , status ) ) {
status = NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
}
2007-05-21 23:35:14 +00:00
/* kill only the first pending receive - this is so that if
that async function frees the connection we don ' t die trying
to use old memory . The caller has to cope with only one
network error */
if ( transport - > pending_recv ) {
2004-08-04 13:23:35 +00:00
struct smbcli_request * req = transport - > pending_recv ;
req - > state = SMBCLI_REQUEST_ERROR ;
2006-07-13 17:37:45 +00:00
req - > status = status ;
2004-08-03 08:04:11 +00:00
DLIST_REMOVE ( transport - > pending_recv , req ) ;
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
}
}
2004-04-23 04:21:22 +00:00
}
2003-08-13 01:53:07 +00:00
2005-01-15 11:58:52 +00:00
/*
send a session request
*/
struct smbcli_request * smbcli_transport_connect_send ( struct smbcli_transport * transport ,
2005-01-21 11:18:56 +00:00
struct nbt_name * calling ,
struct nbt_name * called )
2003-08-13 01:53:07 +00:00
{
2004-12-04 13:56:25 +00:00
uint8_t * p ;
2004-08-04 13:23:35 +00:00
struct smbcli_request * req ;
2005-01-21 11:18:56 +00:00
DATA_BLOB calling_blob , called_blob ;
TALLOC_CTX * tmp_ctx = talloc_new ( transport ) ;
NTSTATUS status ;
2003-08-13 01:53:07 +00:00
2005-01-21 11:18:56 +00:00
status = nbt_name_dup ( transport , called , & transport - > called ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
2010-05-09 17:20:01 +02:00
status = nbt_name_to_blob ( tmp_ctx , & calling_blob , calling ) ;
2005-01-21 11:18:56 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
2010-05-09 17:20:01 +02:00
status = nbt_name_to_blob ( tmp_ctx , & called_blob , called ) ;
2005-01-21 11:18:56 +00:00
if ( ! NT_STATUS_IS_OK ( status ) ) goto failed ;
2003-11-17 03:38:13 +00:00
2003-08-13 01:53:07 +00:00
/* allocate output buffer */
2005-01-15 11:58:52 +00:00
req = smbcli_request_setup_nonsmb ( transport ,
2005-01-21 11:18:56 +00:00
NBT_HDR_SIZE +
calling_blob . length + called_blob . length ) ;
if ( req = = NULL ) goto failed ;
2003-08-13 01:53:07 +00:00
/* put in the destination name */
p = req - > out . buffer + NBT_HDR_SIZE ;
2005-01-21 11:18:56 +00:00
memcpy ( p , called_blob . data , called_blob . length ) ;
p + = called_blob . length ;
2003-08-13 01:53:07 +00:00
2005-01-21 11:18:56 +00:00
memcpy ( p , calling_blob . data , calling_blob . length ) ;
p + = calling_blob . length ;
2003-08-13 01:53:07 +00:00
2011-10-19 14:01:01 +02:00
_smb_setlen_nbt ( req - > out . buffer , PTR_DIFF ( p , req - > out . buffer ) - NBT_HDR_SIZE ) ;
2003-08-13 01:53:07 +00:00
SCVAL ( req - > out . buffer , 0 , 0x81 ) ;
2005-01-15 11:58:52 +00:00
if ( ! smbcli_request_send ( req ) ) {
smbcli_request_destroy ( req ) ;
2005-01-21 11:18:56 +00:00
goto failed ;
2005-01-15 11:58:52 +00:00
}
2005-01-21 11:18:56 +00:00
talloc_free ( tmp_ctx ) ;
2005-01-15 11:58:52 +00:00
return req ;
2005-01-21 11:18:56 +00:00
failed :
talloc_free ( tmp_ctx ) ;
return NULL ;
2005-01-15 11:58:52 +00:00
}
2005-01-16 01:22:08 +00:00
/*
map a session request error to a NTSTATUS
*/
static NTSTATUS map_session_refused_error ( uint8_t error )
{
switch ( error ) {
case 0x80 :
case 0x81 :
return NT_STATUS_REMOTE_NOT_LISTENING ;
case 0x82 :
return NT_STATUS_RESOURCE_NAME_NOT_FOUND ;
case 0x83 :
return NT_STATUS_REMOTE_RESOURCES ;
}
return NT_STATUS_UNEXPECTED_IO_ERROR ;
}
2005-01-15 11:58:52 +00:00
/*
finish a smbcli_transport_connect ( )
*/
2005-01-16 01:22:08 +00:00
NTSTATUS smbcli_transport_connect_recv ( struct smbcli_request * req )
2005-01-15 11:58:52 +00:00
{
2005-01-16 01:22:08 +00:00
NTSTATUS status ;
2005-01-15 11:58:52 +00:00
if ( ! smbcli_request_receive ( req ) ) {
2004-08-04 13:23:35 +00:00
smbcli_request_destroy ( req ) ;
2005-01-16 01:22:08 +00:00
return NT_STATUS_UNEXPECTED_NETWORK_ERROR ;
2003-08-13 01:53:07 +00:00
}
2005-01-15 11:58:52 +00:00
2005-01-16 01:22:08 +00:00
switch ( CVAL ( req - > in . buffer , 0 ) ) {
case 0x82 :
status = NT_STATUS_OK ;
break ;
case 0x83 :
status = map_session_refused_error ( CVAL ( req - > in . buffer , 4 ) ) ;
break ;
case 0x84 :
DEBUG ( 1 , ( " Warning: session retarget not supported \n " ) ) ;
status = NT_STATUS_NOT_SUPPORTED ;
break ;
default :
status = NT_STATUS_UNEXPECTED_IO_ERROR ;
break ;
2003-08-13 01:53:07 +00:00
}
2004-08-04 13:23:35 +00:00
smbcli_request_destroy ( req ) ;
2005-01-16 01:22:08 +00:00
return status ;
2003-08-13 01:53:07 +00:00
}
2005-01-15 11:58:52 +00:00
/*
send a session request ( if needed )
*/
2007-10-06 22:28:14 +00:00
bool smbcli_transport_connect ( struct smbcli_transport * transport ,
2005-01-21 11:18:56 +00:00
struct nbt_name * calling ,
struct nbt_name * called )
2005-01-15 11:58:52 +00:00
{
struct smbcli_request * req ;
2005-01-16 01:22:08 +00:00
NTSTATUS status ;
2005-01-15 11:58:52 +00:00
if ( transport - > socket - > port = = 445 ) {
2007-10-06 22:28:14 +00:00
return true ;
2005-01-15 11:58:52 +00:00
}
req = smbcli_transport_connect_send ( transport ,
calling , called ) ;
2005-01-16 01:22:08 +00:00
status = smbcli_transport_connect_recv ( req ) ;
return NT_STATUS_IS_OK ( status ) ;
2005-01-15 11:58:52 +00:00
}
2003-08-13 01:53:07 +00:00
/****************************************************************************
get next mid in sequence
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-04 13:23:35 +00:00
uint16_t smbcli_transport_next_mid ( struct smbcli_transport * transport )
2003-08-13 01:53:07 +00:00
{
2004-05-25 17:24:24 +00:00
uint16_t mid ;
2004-08-04 13:23:35 +00:00
struct smbcli_request * req ;
2003-08-13 01:53:07 +00:00
mid = transport - > next_mid ;
again :
/* now check to see if this mid is being used by one of the
pending requests . This is quite efficient because the list is
usually very short */
/* the zero mid is reserved for requests that don't have a mid */
if ( mid = = 0 ) mid = 1 ;
2004-07-23 06:40:49 +00:00
for ( req = transport - > pending_recv ; req ; req = req - > next ) {
2003-08-13 01:53:07 +00:00
if ( req - > mid = = mid ) {
mid + + ;
goto again ;
}
}
transport - > next_mid = mid + 1 ;
return mid ;
}
2008-12-29 20:24:57 +01:00
static void idle_handler ( struct tevent_context * ev ,
2009-02-02 08:24:59 +01:00
struct tevent_timer * te , struct timeval t , void * private_data )
2004-07-23 06:40:49 +00:00
{
2009-02-02 08:24:59 +01:00
struct smbcli_transport * transport = talloc_get_type ( private_data ,
2005-02-03 02:35:52 +00:00
struct smbcli_transport ) ;
struct timeval next = timeval_add ( & t , 0 , transport - > idle . period ) ;
2010-05-25 15:26:42 -04:00
transport - > socket - > event . te = tevent_add_timer ( transport - > socket - > event . ctx ,
2005-02-03 02:35:52 +00:00
transport ,
next ,
idle_handler , transport ) ;
2009-02-02 10:17:00 +01:00
transport - > idle . func ( transport , transport - > idle . private_data ) ;
2004-07-23 06:40:49 +00:00
}
2003-08-13 01:53:07 +00:00
/*
setup the idle handler for a transport
2004-11-03 10:09:48 +00:00
the period is in microseconds
2003-08-13 01:53:07 +00:00
*/
2008-04-02 04:53:27 +02:00
_PUBLIC_ void smbcli_transport_idle_handler ( struct smbcli_transport * transport ,
2004-11-03 10:09:48 +00:00
void ( * idle_func ) ( struct smbcli_transport * , void * ) ,
uint64_t period ,
2009-02-02 08:24:59 +01:00
void * private_data )
2003-08-13 01:53:07 +00:00
{
transport - > idle . func = idle_func ;
2009-02-02 10:17:00 +01:00
transport - > idle . private_data = private_data ;
2003-08-13 01:53:07 +00:00
transport - > idle . period = period ;
2005-01-15 10:38:12 +00:00
if ( transport - > socket - > event . te ! = NULL ) {
2005-01-24 01:51:45 +00:00
talloc_free ( transport - > socket - > event . te ) ;
2004-07-23 06:40:49 +00:00
}
2010-05-25 15:26:42 -04:00
transport - > socket - > event . te = tevent_add_timer ( transport - > socket - > event . ctx ,
2005-02-03 02:35:52 +00:00
transport ,
2011-06-01 11:24:51 +09:30
timeval_current_ofs_usec ( period ) ,
2005-02-03 02:35:52 +00:00
idle_handler , transport ) ;
2004-07-23 06:40:49 +00:00
}
2003-08-13 01:53:07 +00:00
/*
2004-07-23 06:40:49 +00:00
we have a full request in our receive buffer - match it to a pending request
and process
*/
2009-02-02 08:24:59 +01:00
static NTSTATUS smbcli_transport_finish_recv ( void * private_data , DATA_BLOB blob )
2003-08-13 01:53:07 +00:00
{
2009-02-02 08:24:59 +01:00
struct smbcli_transport * transport = talloc_get_type ( private_data ,
2005-11-09 08:13:41 +00:00
struct smbcli_transport ) ;
2004-07-23 06:40:49 +00:00
uint8_t * buffer , * hdr , * vwv ;
int len ;
2005-10-06 05:25:35 +00:00
uint16_t wct = 0 , mid = 0 , op = 0 ;
2005-11-11 07:38:25 +00:00
struct smbcli_request * req = NULL ;
2003-08-13 01:53:07 +00:00
2005-11-09 08:13:41 +00:00
buffer = blob . data ;
len = blob . length ;
2004-08-03 06:52:06 +00:00
2004-07-23 06:40:49 +00:00
hdr = buffer + NBT_HDR_SIZE ;
vwv = hdr + HDR_VWV ;
/* see if it could be an oplock break request */
2005-11-10 15:27:27 +00:00
if ( smbcli_handle_oplock_break ( transport , len , hdr , vwv ) ) {
2004-08-21 01:54:46 +00:00
talloc_free ( buffer ) ;
2005-11-09 08:13:41 +00:00
return NT_STATUS_OK ;
2003-08-13 01:53:07 +00:00
}
2004-07-23 06:40:49 +00:00
/* at this point we need to check for a readbraw reply, as
these can be any length */
if ( transport - > readbraw_pending ) {
transport - > readbraw_pending = 0 ;
/* it must match the first entry in the pending queue
as the client is not allowed to have outstanding
readbraw requests */
req = transport - > pending_recv ;
if ( ! req ) goto error ;
req - > in . buffer = buffer ;
2004-08-21 02:07:12 +00:00
talloc_steal ( req , buffer ) ;
2004-07-29 09:30:54 +00:00
req - > in . size = len ;
2004-07-23 06:40:49 +00:00
req - > in . allocated = req - > in . size ;
goto async ;
}
2003-08-13 01:53:07 +00:00
2004-07-23 06:40:49 +00:00
if ( len > = MIN_SMB_SIZE ) {
/* extract the mid for matching to pending requests */
mid = SVAL ( hdr , HDR_MID ) ;
wct = CVAL ( hdr , HDR_WCT ) ;
2005-10-06 05:25:35 +00:00
op = CVAL ( hdr , HDR_COM ) ;
2004-07-23 06:40:49 +00:00
}
/* match the incoming request against the list of pending requests */
for ( req = transport - > pending_recv ; req ; req = req - > next ) {
if ( req - > mid = = mid ) break ;
}
2005-11-10 16:09:44 +00:00
/* see if it's a ntcancel reply for the current MID */
req = smbcli_handle_ntcancel_reply ( req , len , hdr ) ;
2004-07-23 06:40:49 +00:00
if ( ! req ) {
2005-10-06 05:25:35 +00:00
DEBUG ( 1 , ( " Discarding unmatched reply with mid %d op %d \n " , mid , op ) ) ;
2004-07-23 06:40:49 +00:00
goto error ;
}
/* fill in the 'in' portion of the matching request */
req - > in . buffer = buffer ;
2004-08-21 02:07:12 +00:00
talloc_steal ( req , buffer ) ;
2004-07-29 09:30:54 +00:00
req - > in . size = len ;
2004-07-23 06:40:49 +00:00
req - > in . allocated = req - > in . size ;
2004-08-14 18:24:33 +00:00
/* handle NBT session replies */
2004-08-18 20:07:44 +00:00
if ( req - > in . size > = 4 & & req - > in . buffer [ 0 ] ! = 0 ) {
2004-08-14 18:24:33 +00:00
req - > status = NT_STATUS_OK ;
goto async ;
}
2004-07-23 06:40:49 +00:00
/* handle non-SMB replies */
if ( req - > in . size < NBT_HDR_SIZE + MIN_SMB_SIZE ) {
2004-08-04 13:23:35 +00:00
req - > state = SMBCLI_REQUEST_ERROR ;
2004-07-23 06:40:49 +00:00
goto error ;
}
if ( req - > in . size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV ( wct ) ) {
DEBUG ( 2 , ( " bad reply size for mid %d \n " , mid ) ) ;
req - > status = NT_STATUS_UNSUCCESSFUL ;
2004-08-04 13:23:35 +00:00
req - > state = SMBCLI_REQUEST_ERROR ;
2004-07-23 06:40:49 +00:00
goto error ;
}
req - > in . hdr = hdr ;
req - > in . vwv = vwv ;
req - > in . wct = wct ;
if ( req - > in . size > = NBT_HDR_SIZE + MIN_SMB_SIZE + VWV ( wct ) ) {
req - > in . data = req - > in . vwv + VWV ( wct ) + 2 ;
req - > in . data_size = SVAL ( req - > in . vwv , VWV ( wct ) ) ;
if ( req - > in . size < NBT_HDR_SIZE + MIN_SMB_SIZE + VWV ( wct ) + req - > in . data_size ) {
DEBUG ( 3 , ( " bad data size for mid %d \n " , mid ) ) ;
/* blergh - w2k3 gives a bogus data size values in some
openX replies */
req - > in . data_size = req - > in . size - ( NBT_HDR_SIZE + MIN_SMB_SIZE + VWV ( wct ) ) ;
2003-08-13 01:53:07 +00:00
}
2004-07-23 06:40:49 +00:00
}
req - > in . ptr = req - > in . data ;
req - > flags2 = SVAL ( req - > in . hdr , HDR_FLG2 ) ;
2008-02-14 10:12:33 +11:00
smb_setup_bufinfo ( req ) ;
2004-07-23 06:40:49 +00:00
if ( ! ( req - > flags2 & FLAGS2_32_BIT_ERROR_CODES ) ) {
2009-02-02 11:00:08 +01:00
int eclass = CVAL ( req - > in . hdr , HDR_RCLS ) ;
2005-07-04 01:23:38 +00:00
int code = SVAL ( req - > in . hdr , HDR_ERR ) ;
2009-02-02 11:00:08 +01:00
if ( eclass = = 0 & & code = = 0 ) {
2005-07-04 01:23:38 +00:00
transport - > error . e . nt_status = NT_STATUS_OK ;
} else {
2009-02-02 11:00:08 +01:00
transport - > error . e . nt_status = NT_STATUS_DOS ( eclass , code ) ;
2005-07-04 01:23:38 +00:00
}
2004-07-23 06:40:49 +00:00
} else {
transport - > error . e . nt_status = NT_STATUS ( IVAL ( req - > in . hdr , HDR_RCLS ) ) ;
2005-07-04 01:23:38 +00:00
}
req - > status = transport - > error . e . nt_status ;
if ( NT_STATUS_IS_OK ( req - > status ) ) {
transport - > error . etype = ETYPE_NONE ;
} else {
transport - > error . etype = ETYPE_SMB ;
2004-07-23 06:40:49 +00:00
}
2004-08-04 13:23:35 +00:00
if ( ! smbcli_request_check_sign_mac ( req ) ) {
2004-07-23 06:40:49 +00:00
transport - > error . etype = ETYPE_SOCKET ;
transport - > error . e . socket_error = SOCKET_READ_BAD_SIG ;
2004-08-04 13:23:35 +00:00
req - > state = SMBCLI_REQUEST_ERROR ;
2004-12-16 12:25:23 +00:00
req - > status = NT_STATUS_ACCESS_DENIED ;
2004-07-23 06:40:49 +00:00
goto error ;
} ;
async :
/* if this request has an async handler then call that to
notify that the reply has been received . This might destroy
the request so it must happen last */
2008-07-04 19:52:23 +02:00
2004-08-04 13:23:35 +00:00
req - > state = SMBCLI_REQUEST_DONE ;
2008-07-04 19:52:23 +02:00
if ( req - > recv_helper . fn ) {
/*
* let the recv helper decide in
* what state the request really is
*/
req - > state = req - > recv_helper . fn ( req ) ;
/* if more parts are needed, wait for them */
if ( req - > state < = SMBCLI_REQUEST_RECV ) {
return NT_STATUS_OK ;
}
}
DLIST_REMOVE ( transport - > pending_recv , req ) ;
2004-07-23 06:40:49 +00:00
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
}
2005-11-09 08:13:41 +00:00
return NT_STATUS_OK ;
2004-07-23 06:40:49 +00:00
error :
if ( req ) {
DLIST_REMOVE ( transport - > pending_recv , req ) ;
2004-08-04 13:23:35 +00:00
req - > state = SMBCLI_REQUEST_ERROR ;
2005-11-11 07:38:25 +00:00
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
}
2005-11-10 14:16:50 +00:00
} else {
talloc_free ( buffer ) ;
2004-07-23 06:40:49 +00:00
}
2005-11-09 08:13:41 +00:00
return NT_STATUS_OK ;
2004-07-23 06:40:49 +00:00
}
2003-08-13 01:53:07 +00:00
2004-07-23 06:40:49 +00:00
/*
process some read / write requests that are pending
2007-10-06 22:28:14 +00:00
return false if the socket is dead
2004-07-23 06:40:49 +00:00
*/
2008-04-02 04:53:27 +02:00
_PUBLIC_ bool smbcli_transport_process ( struct smbcli_transport * transport )
2004-07-23 06:40:49 +00:00
{
2005-11-09 08:13:41 +00:00
NTSTATUS status ;
size_t npending ;
2005-11-09 13:34:36 +00:00
packet_queue_run ( transport - > packet ) ;
2005-11-09 08:13:41 +00:00
if ( transport - > socket - > sock = = NULL ) {
2007-10-06 22:28:14 +00:00
return false ;
2005-11-09 08:13:41 +00:00
}
status = socket_pending ( transport - > socket - > sock , & npending ) ;
if ( NT_STATUS_IS_OK ( status ) & & npending > 0 ) {
packet_recv ( transport - > packet ) ;
}
2004-10-28 08:15:12 +00:00
if ( transport - > socket - > sock = = NULL ) {
2007-10-06 22:28:14 +00:00
return false ;
2004-07-23 06:40:49 +00:00
}
2007-10-06 22:28:14 +00:00
return true ;
2003-08-13 01:53:07 +00:00
}
2004-04-07 07:18:37 +00:00
2005-06-16 23:19:03 +00:00
/*
handle timeouts of individual smb requests
*/
2008-12-29 20:24:57 +01:00
static void smbcli_timeout_handler ( struct tevent_context * ev , struct tevent_timer * te ,
2009-02-02 08:24:59 +01:00
struct timeval t , void * private_data )
2005-06-16 23:19:03 +00:00
{
2009-02-02 08:24:59 +01:00
struct smbcli_request * req = talloc_get_type ( private_data , struct smbcli_request ) ;
2005-06-16 23:19:03 +00:00
if ( req - > state = = SMBCLI_REQUEST_RECV ) {
DLIST_REMOVE ( req - > transport - > pending_recv , req ) ;
}
req - > status = NT_STATUS_IO_TIMEOUT ;
req - > state = SMBCLI_REQUEST_ERROR ;
if ( req - > async . fn ) {
req - > async . fn ( req ) ;
}
}
/*
destroy a request
*/
2006-05-24 07:34:11 +00:00
static int smbcli_request_destructor ( struct smbcli_request * req )
2005-06-16 23:19:03 +00:00
{
if ( req - > state = = SMBCLI_REQUEST_RECV ) {
DLIST_REMOVE ( req - > transport - > pending_recv , req ) ;
}
return 0 ;
}
2004-07-23 06:40:49 +00:00
/*
put a request into the send queue
*/
2004-08-04 13:23:35 +00:00
void smbcli_transport_send ( struct smbcli_request * req )
2004-07-23 06:40:49 +00:00
{
2005-11-09 13:34:36 +00:00
DATA_BLOB blob ;
NTSTATUS status ;
2004-08-03 08:04:11 +00:00
/* check if the transport is dead */
2004-10-28 08:15:12 +00:00
if ( req - > transport - > socket - > sock = = NULL ) {
2004-08-04 13:23:35 +00:00
req - > state = SMBCLI_REQUEST_ERROR ;
2004-08-03 08:04:11 +00:00
req - > status = NT_STATUS_NET_WRITE_FAULT ;
return ;
}
2005-11-09 13:34:36 +00:00
blob = data_blob_const ( req - > out . buffer , req - > out . size ) ;
status = packet_send ( req - > transport - > packet , blob ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
req - > state = SMBCLI_REQUEST_ERROR ;
req - > status = status ;
return ;
}
2004-07-23 06:40:49 +00:00
2009-06-09 12:51:44 +01:00
packet_queue_run ( req - > transport - > packet ) ;
if ( req - > transport - > socket - > sock = = NULL ) {
req - > state = SMBCLI_REQUEST_ERROR ;
req - > status = NT_STATUS_NET_WRITE_FAULT ;
return ;
}
2005-11-09 13:34:36 +00:00
if ( req - > one_way_request ) {
req - > state = SMBCLI_REQUEST_DONE ;
smbcli_request_destroy ( req ) ;
2005-11-09 14:00:31 +00:00
return ;
2005-11-09 13:34:36 +00:00
}
2005-06-16 23:19:03 +00:00
2005-11-09 14:00:31 +00:00
req - > state = SMBCLI_REQUEST_RECV ;
DLIST_ADD ( req - > transport - > pending_recv , req ) ;
2005-06-16 23:19:03 +00:00
/* add a timeout */
if ( req - > transport - > options . request_timeout ) {
2010-05-25 15:26:42 -04:00
tevent_add_timer ( req - > transport - > socket - > event . ctx , req ,
2005-06-16 23:19:03 +00:00
timeval_current_ofs ( req - > transport - > options . request_timeout , 0 ) ,
smbcli_timeout_handler , req ) ;
}
talloc_set_destructor ( req , smbcli_request_destructor ) ;
2004-07-23 06:40:49 +00:00
}
2007-05-25 10:42:29 +00:00
/****************************************************************************
Send an SMBecho ( async send )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-04-02 04:53:27 +02:00
_PUBLIC_ struct smbcli_request * smb_raw_echo_send ( struct smbcli_transport * transport ,
2007-05-25 10:42:29 +00:00
struct smb_echo * p )
{
struct smbcli_request * req ;
req = smbcli_request_setup_transport ( transport , SMBecho , 1 , p - > in . size ) ;
if ( ! req ) return NULL ;
SSVAL ( req - > out . vwv , VWV ( 0 ) , p - > in . repeat_count ) ;
memcpy ( req - > out . data , p - > in . data , p - > in . size ) ;
ZERO_STRUCT ( p - > out ) ;
if ( ! smbcli_request_send ( req ) ) {
smbcli_request_destroy ( req ) ;
return NULL ;
}
return req ;
}
/****************************************************************************
raw echo interface ( async recv )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS smb_raw_echo_recv ( struct smbcli_request * req , TALLOC_CTX * mem_ctx ,
struct smb_echo * p )
{
if ( ! smbcli_request_receive ( req ) | |
smbcli_request_is_error ( req ) ) {
goto failed ;
}
SMBCLI_CHECK_WCT ( req , 1 ) ;
p - > out . count + + ;
p - > out . sequence_number = SVAL ( req - > in . vwv , VWV ( 0 ) ) ;
p - > out . size = req - > in . data_size ;
talloc_free ( p - > out . data ) ;
2007-09-07 13:31:15 +00:00
p - > out . data = talloc_array ( mem_ctx , uint8_t , p - > out . size ) ;
2007-05-25 10:42:29 +00:00
NT_STATUS_HAVE_NO_MEMORY ( p - > out . data ) ;
2008-02-14 10:12:33 +11:00
if ( ! smbcli_raw_pull_data ( & req - > in . bufinfo , req - > in . data , p - > out . size , p - > out . data ) ) {
2007-05-25 10:42:29 +00:00
req - > status = NT_STATUS_BUFFER_TOO_SMALL ;
}
if ( p - > out . count = = p - > in . repeat_count ) {
return smbcli_request_destroy ( req ) ;
}
return NT_STATUS_OK ;
failed :
return smbcli_request_destroy ( req ) ;
}
/****************************************************************************
Send a echo ( sync interface )
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
NTSTATUS smb_raw_echo ( struct smbcli_transport * transport , struct smb_echo * p )
{
struct smbcli_request * req = smb_raw_echo_send ( transport , p ) ;
return smbcli_request_simple_recv ( req ) ;
}