2003-08-13 01:53:07 +00:00
/*
Unix SMB / CIFS implementation .
SMB client socket context management functions
2005-01-15 10:38:12 +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
the Free Software Foundation ; either version 2 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 , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
2005-01-15 10:38:12 +00:00
# include "events.h"
2004-11-01 01:03:22 +00:00
# include "libcli/raw/libcliraw.h"
2005-01-15 10:38:12 +00:00
# include "libcli/composite/composite.h"
/*
this private structure is used during async connection handling
*/
struct clisocket_connect {
int * iports ;
struct smbcli_socket * sock ;
const char * dest_host ;
} ;
2003-08-13 01:53:07 +00:00
/*
2004-08-04 13:23:35 +00:00
create a smbcli_socket context
2003-08-13 01:53:07 +00:00
*/
2004-09-28 05:44:59 +00:00
struct smbcli_socket * smbcli_sock_init ( TALLOC_CTX * mem_ctx )
2003-08-13 01:53:07 +00:00
{
2004-08-04 13:23:35 +00:00
struct smbcli_socket * sock ;
2003-08-13 01:53:07 +00:00
2005-01-15 10:38:12 +00:00
sock = talloc_zero ( mem_ctx , struct smbcli_socket ) ;
2003-08-13 01:53:07 +00:00
if ( ! sock ) {
return NULL ;
}
2005-01-15 10:38:12 +00:00
sock - > event . ctx = event_context_init ( sock ) ;
if ( sock - > event . ctx = = NULL ) {
talloc_free ( sock ) ;
return NULL ;
}
2004-07-13 05:14:59 +00:00
2003-08-13 01:53:07 +00:00
return sock ;
}
2005-01-15 10:38:12 +00:00
static NTSTATUS smbcli_sock_connect_one ( struct smbcli_socket * sock ,
const char * hostaddr , int port ) ;
2003-08-13 01:53:07 +00:00
/*
2005-01-15 10:38:12 +00:00
handle socket write events during an async connect . These happen when the OS
has either completed the connect ( ) or has returned an error
2003-08-13 01:53:07 +00:00
*/
2005-01-15 10:38:12 +00:00
static void smbcli_sock_connect_handler ( struct event_context * ev , struct fd_event * fde ,
struct timeval t , uint16_t flags )
2003-08-13 01:53:07 +00:00
{
2005-01-15 10:38:12 +00:00
struct smbcli_composite * c = fde - > private ;
struct clisocket_connect * conn = c - > private ;
int i ;
c - > status = socket_connect_complete ( conn - > sock - > sock , 0 ) ;
if ( NT_STATUS_IS_OK ( c - > status ) ) {
socket_set_option ( conn - > sock - > sock , lp_socket_options ( ) , NULL ) ;
c - > state = SMBCLI_REQUEST_DONE ;
if ( c - > async . fn ) {
c - > async . fn ( c ) ;
}
return ;
}
2003-08-13 01:53:07 +00:00
2005-01-15 10:38:12 +00:00
/* that port failed - try the next port */
for ( i = c - > stage + 1 ; conn - > iports [ i ] ; i + + ) {
c - > stage = i ;
c - > status = smbcli_sock_connect_one ( conn - > sock ,
conn - > dest_host ,
conn - > iports [ i ] ) ;
2005-01-16 01:21:18 +00:00
if ( NT_STATUS_IS_OK ( c - > status ) | |
NT_STATUS_EQUAL ( c - > status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
2005-01-15 10:38:12 +00:00
conn - > sock - > event . fde - > private = c ;
return ;
}
2003-08-13 01:53:07 +00:00
}
2005-01-15 10:38:12 +00:00
c - > state = SMBCLI_REQUEST_ERROR ;
if ( c - > async . fn ) {
c - > async . fn ( c ) ;
2004-07-23 06:40:49 +00:00
}
2005-01-15 10:38:12 +00:00
}
2004-07-23 06:40:49 +00:00
2005-01-15 10:38:12 +00:00
/*
try to connect to the given address / port
*/
static NTSTATUS smbcli_sock_connect_one ( struct smbcli_socket * sock ,
const char * hostaddr , int port )
{
struct fd_event fde ;
NTSTATUS status ;
if ( sock - > sock ) {
2004-10-28 08:15:12 +00:00
talloc_free ( sock - > sock ) ;
sock - > sock = NULL ;
}
2005-01-15 10:38:12 +00:00
if ( sock - > event . fde ) {
event_remove_fd ( sock - > event . ctx , sock - > event . fde ) ;
sock - > event . fde = NULL ;
}
status = socket_create ( " ip " , SOCKET_TYPE_STREAM , & sock - > sock , 0 ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
talloc_steal ( sock , sock - > sock ) ;
/* we initially look for write - see the man page on
non - blocking connect */
fde . fd = socket_get_fd ( sock - > sock ) ;
fde . flags = EVENT_FD_WRITE ;
fde . handler = smbcli_sock_connect_handler ;
fde . private = sock ;
sock - > event . fde = event_add_fd ( sock - > event . ctx , & fde ) ;
2004-10-28 08:15:12 +00:00
sock - > port = port ;
2005-01-15 10:38:12 +00:00
set_blocking ( fde . fd , False ) ;
return socket_connect ( sock - > sock , NULL , 0 , hostaddr , port , 0 ) ;
}
2004-10-28 08:15:12 +00:00
2005-01-15 10:38:12 +00:00
/*
connect a smbcli_socket context to an IP / port pair
if port is 0 then choose 445 then 139
this is the async send side of the interface
*/
struct smbcli_composite * smbcli_sock_connect_send ( struct smbcli_socket * sock ,
2005-01-16 01:21:18 +00:00
const char * host_addr , int port )
2005-01-15 10:38:12 +00:00
{
struct smbcli_composite * c ;
struct clisocket_connect * conn ;
int i ;
c = talloc_zero ( sock , struct smbcli_composite ) ;
if ( c = = NULL ) return NULL ;
c - > event_ctx = sock - > event . ctx ;
conn = talloc ( c , struct clisocket_connect ) ;
if ( conn = = NULL ) goto failed ;
conn - > sock = sock ;
/* work out what ports we will try */
if ( port = = 0 ) {
const char * * ports = lp_smb_ports ( ) ;
for ( i = 0 ; ports [ i ] ; i + + ) /* noop */ ;
conn - > iports = talloc_array ( c , int , i + 1 ) ;
if ( conn - > iports = = NULL ) goto failed ;
for ( i = 0 ; ports [ i ] ; i + + ) {
conn - > iports [ i ] = atoi ( ports [ i ] ) ;
}
conn - > iports [ i ] = 0 ;
} else {
conn - > iports = talloc_array ( c , int , 2 ) ;
if ( conn - > iports = = NULL ) goto failed ;
conn - > iports [ 0 ] = port ;
conn - > iports [ 1 ] = 0 ;
}
2004-07-23 06:40:49 +00:00
2005-01-16 01:21:18 +00:00
conn - > dest_host = talloc_strdup ( c , host_addr ) ;
2005-01-15 10:38:12 +00:00
if ( conn - > dest_host = = NULL ) goto failed ;
c - > private = conn ;
c - > state = SMBCLI_REQUEST_SEND ;
/* startup the connect process for each port in turn until one
succeeds or tells us that it is pending */
for ( i = 0 ; conn - > iports [ i ] ; i + + ) {
c - > stage = i ;
conn - > sock - > port = conn - > iports [ i ] ;
c - > status = smbcli_sock_connect_one ( sock ,
conn - > dest_host ,
conn - > iports [ i ] ) ;
2005-01-16 01:21:18 +00:00
if ( NT_STATUS_IS_OK ( c - > status ) | |
NT_STATUS_EQUAL ( c - > status , NT_STATUS_MORE_PROCESSING_REQUIRED ) ) {
2005-01-15 10:38:12 +00:00
sock - > event . fde - > private = c ;
return c ;
}
}
c - > state = SMBCLI_REQUEST_ERROR ;
return c ;
failed :
talloc_free ( c ) ;
return NULL ;
}
/*
finish a smbcli_sock_connect_send ( ) operation
*/
NTSTATUS smbcli_sock_connect_recv ( struct smbcli_composite * c )
{
NTSTATUS status ;
status = smb_composite_wait ( c ) ;
talloc_free ( c ) ;
return status ;
}
/*
connect a smbcli_socket context to an IP / port pair
if port is 0 then choose the ports listed in smb . conf ( normally 445 then 139 )
sync version of the function
*/
2005-01-16 01:21:18 +00:00
NTSTATUS smbcli_sock_connect ( struct smbcli_socket * sock , const char * host_addr , int port )
2005-01-15 10:38:12 +00:00
{
struct smbcli_composite * c ;
2005-01-16 01:21:18 +00:00
c = smbcli_sock_connect_send ( sock , host_addr , port ) ;
2005-01-15 10:38:12 +00:00
if ( c = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
return smbcli_sock_connect_recv ( c ) ;
2003-08-13 01:53:07 +00:00
}
2004-04-23 04:21:22 +00:00
/****************************************************************************
mark the socket as dead
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-04 13:23:35 +00:00
void smbcli_sock_dead ( struct smbcli_socket * sock )
2004-04-23 04:21:22 +00:00
{
2004-10-28 08:15:12 +00:00
if ( sock - > sock ! = NULL ) {
talloc_free ( sock - > sock ) ;
sock - > sock = NULL ;
2004-04-23 04:21:22 +00:00
}
}
2003-08-13 01:53:07 +00:00
/****************************************************************************
Set socket options on a open connection .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-04 13:23:35 +00:00
void smbcli_sock_set_options ( struct smbcli_socket * sock , const char * options )
2003-08-13 01:53:07 +00:00
{
2004-10-28 08:15:12 +00:00
socket_set_option ( sock - > sock , options , NULL ) ;
2003-08-13 01:53:07 +00:00
}
/****************************************************************************
Write to socket . Return amount written .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-12-04 13:56:25 +00:00
ssize_t smbcli_sock_write ( struct smbcli_socket * sock , const uint8_t * data , size_t len )
2003-08-13 01:53:07 +00:00
{
2004-10-28 08:15:12 +00:00
NTSTATUS status ;
DATA_BLOB blob ;
size_t nsent ;
if ( sock - > sock = = NULL ) {
2004-04-23 04:21:22 +00:00
errno = EIO ;
return - 1 ;
}
2004-10-28 08:15:12 +00:00
blob . data = discard_const ( data ) ;
blob . length = len ;
status = socket_send ( sock - > sock , & blob , & nsent , 0 ) ;
if ( NT_STATUS_IS_ERR ( status ) ) {
return - 1 ;
}
return nsent ;
2003-08-13 01:53:07 +00:00
}
/****************************************************************************
Read from socket . return amount read
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-12-04 13:56:25 +00:00
ssize_t smbcli_sock_read ( struct smbcli_socket * sock , uint8_t * data , size_t len )
2003-08-13 01:53:07 +00:00
{
2004-10-28 08:15:12 +00:00
NTSTATUS status ;
size_t nread ;
if ( sock - > sock = = NULL ) {
2004-04-23 04:21:22 +00:00
errno = EIO ;
return - 1 ;
}
2004-10-28 08:15:12 +00:00
status = socket_recv ( sock - > sock , data , len , & nread , 0 ) ;
if ( NT_STATUS_IS_ERR ( status ) ) {
return - 1 ;
}
return nread ;
2003-08-13 01:53:07 +00:00
}
2005-01-15 10:38:12 +00:00
2003-08-13 01:53:07 +00:00
/****************************************************************************
resolve a hostname and connect
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-04 13:23:35 +00:00
BOOL smbcli_sock_connect_byname ( struct smbcli_socket * sock , const char * host , int port )
2003-08-13 01:53:07 +00:00
{
int name_type = 0x20 ;
2004-11-01 22:48:25 +00:00
struct ipv4_addr ip ;
2003-08-13 01:53:07 +00:00
char * name , * p ;
2005-01-15 10:38:12 +00:00
NTSTATUS status ;
2003-08-13 01:53:07 +00:00
2004-08-21 07:43:29 +00:00
name = talloc_strdup ( sock , host ) ;
2003-08-13 01:53:07 +00:00
/* allow hostnames of the form NAME#xx and do a netbios lookup */
if ( ( p = strchr ( name , ' # ' ) ) ) {
name_type = strtol ( p + 1 , NULL , 16 ) ;
* p = 0 ;
}
2004-08-21 07:43:29 +00:00
if ( ! resolve_name ( name , name , & ip , name_type ) ) {
2003-08-13 01:53:07 +00:00
return False ;
}
2005-01-15 10:38:12 +00:00
sock - > hostname = name ;
2004-07-13 05:14:59 +00:00
2005-01-16 01:21:18 +00:00
status = smbcli_sock_connect ( sock , sys_inet_ntoa ( ip ) , port ) ;
2004-07-13 05:14:59 +00:00
2005-01-15 10:38:12 +00:00
return NT_STATUS_IS_OK ( status ) ;
2003-08-13 01:53:07 +00:00
}