1998-08-17 17:11:34 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-08-17 17:11:34 +04:00
process incoming packets - main loop
Copyright ( C ) Andrew Tridgell 1992 - 1998
2007-08-02 22:28:41 +04:00
Copyright ( C ) Volker Lendecke 2005 - 2007
2011-02-03 23:47:42 +03:00
1998-08-17 17:11:34 +04:00
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-09 23:25:36 +04:00
the Free Software Foundation ; either version 3 of the License , or
1998-08-17 17:11:34 +04:00
( at your option ) any later version .
2011-02-03 23:47:42 +03:00
1998-08-17 17:11:34 +04:00
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 .
2011-02-03 23:47:42 +03:00
1998-08-17 17:11:34 +04:00
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1998-08-17 17:11:34 +04:00
*/
# include "includes.h"
2011-04-28 19:26:40 +04:00
# include "../lib/tsocket/tsocket.h"
2011-02-26 01:20:06 +03:00
# include "system/filesys.h"
2011-03-22 18:57:01 +03:00
# include "smbd/smbd.h"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
2010-08-10 14:29:27 +04:00
# include "librpc/gen_ndr/netlogon.h"
2010-08-26 11:58:09 +04:00
# include "../lib/async_req/async_sock.h"
2010-08-26 12:14:07 +04:00
# include "ctdbd_conn.h"
2010-10-01 12:08:15 +04:00
# include "../lib/util/select.h"
2011-08-02 00:50:51 +04:00
# include "printing/queue_process.h"
2011-02-03 23:55:02 +03:00
# include "system/select.h"
2011-03-22 18:50:02 +03:00
# include "passdb.h"
2011-03-24 15:46:20 +03:00
# include "auth.h"
2011-03-24 17:31:06 +03:00
# include "messages.h"
2011-04-14 02:36:23 +04:00
# include "smbprofile.h"
2011-04-30 01:47:25 +04:00
# include "rpc_server/spoolss/srv_spoolss_nt.h"
2011-05-06 13:47:43 +04:00
# include "libsmb/libsmb.h"
2011-07-26 17:07:22 +04:00
# include "../lib/util/tevent_ntstatus.h"
2011-12-14 13:23:30 +04:00
# include "../libcli/security/dom_sid.h"
# include "../libcli/security/security_token.h"
# include "lib/id_cache.h"
2012-05-24 15:46:11 +04:00
# include "serverid.h"
1998-08-17 17:11:34 +04:00
2011-12-12 14:19:05 +04:00
/* Internal message queue for deferred opens. */
struct pending_message_list {
struct pending_message_list * next , * prev ;
struct timeval request_time ; /* When was this first issued? */
struct smbd_server_connection * sconn ;
struct timed_event * te ;
struct smb_perfcount_data pcd ;
uint32_t seqnum ;
bool encrypted ;
bool processed ;
DATA_BLOB buf ;
DATA_BLOB private_data ;
} ;
2008-12-19 20:07:44 +03:00
static void construct_reply_common ( struct smb_request * req , const char * inbuf ,
char * outbuf ) ;
2011-08-02 19:07:25 +04:00
static struct pending_message_list * get_deferred_open_message_smb (
struct smbd_server_connection * sconn , uint64_t mid ) ;
2012-02-28 03:56:10 +04:00
static bool smb_splice_chain ( uint8_t * * poutbuf , const uint8_t * andx_buf ) ;
2008-11-07 23:02:11 +03:00
2010-04-01 04:40:30 +04:00
static bool smbd_lock_socket_internal ( struct smbd_server_connection * sconn )
2010-03-18 11:17:43 +03:00
{
2010-03-18 14:50:22 +03:00
bool ok ;
2010-06-12 13:06:24 +04:00
if ( sconn - > smb1 . echo_handler . socket_lock_fd = = - 1 ) {
2010-03-18 14:50:22 +03:00
return true ;
}
2010-06-12 13:06:24 +04:00
sconn - > smb1 . echo_handler . ref_count + + ;
2010-04-01 04:40:30 +04:00
2010-06-12 13:06:24 +04:00
if ( sconn - > smb1 . echo_handler . ref_count > 1 ) {
2010-04-01 04:40:30 +04:00
return true ;
}
2012-03-24 23:17:08 +04:00
DEBUG ( 10 , ( " pid[%d] wait for socket lock \n " , ( int ) getpid ( ) ) ) ;
2010-03-18 14:50:22 +03:00
2010-10-19 10:53:21 +04:00
do {
ok = fcntl_lock (
sconn - > smb1 . echo_handler . socket_lock_fd ,
2012-03-28 06:32:54 +04:00
F_SETLKW , 0 , 0 , F_WRLCK ) ;
2010-10-19 10:53:21 +04:00
} while ( ! ok & & ( errno = = EINTR ) ) ;
2010-03-18 14:50:22 +03:00
if ( ! ok ) {
2010-10-19 10:59:14 +04:00
DEBUG ( 1 , ( " fcntl_lock failed: %s \n " , strerror ( errno ) ) ) ;
2010-03-18 14:50:22 +03:00
return false ;
}
2012-03-24 23:17:08 +04:00
DEBUG ( 10 , ( " pid[%d] got for socket lock \n " , ( int ) getpid ( ) ) ) ;
2010-03-18 14:50:22 +03:00
2010-03-18 11:17:43 +03:00
return true ;
}
2010-04-01 04:40:30 +04:00
void smbd_lock_socket ( struct smbd_server_connection * sconn )
{
if ( ! smbd_lock_socket_internal ( sconn ) ) {
exit_server_cleanly ( " failed to lock socket " ) ;
}
}
static bool smbd_unlock_socket_internal ( struct smbd_server_connection * sconn )
2010-03-18 11:17:43 +03:00
{
2010-03-18 14:50:22 +03:00
bool ok ;
2010-06-12 13:06:24 +04:00
if ( sconn - > smb1 . echo_handler . socket_lock_fd = = - 1 ) {
2010-03-18 14:50:22 +03:00
return true ;
}
2010-06-12 13:06:24 +04:00
sconn - > smb1 . echo_handler . ref_count - - ;
2010-04-01 04:40:30 +04:00
2010-06-12 13:06:24 +04:00
if ( sconn - > smb1 . echo_handler . ref_count > 0 ) {
2010-04-01 04:40:30 +04:00
return true ;
}
2010-10-19 10:53:21 +04:00
do {
ok = fcntl_lock (
sconn - > smb1 . echo_handler . socket_lock_fd ,
2012-03-28 06:32:54 +04:00
F_SETLKW , 0 , 0 , F_UNLCK ) ;
2010-10-19 10:53:21 +04:00
} while ( ! ok & & ( errno = = EINTR ) ) ;
2010-03-18 14:50:22 +03:00
if ( ! ok ) {
2010-10-19 10:59:14 +04:00
DEBUG ( 1 , ( " fcntl_lock failed: %s \n " , strerror ( errno ) ) ) ;
2010-03-18 14:50:22 +03:00
return false ;
}
2012-03-24 23:17:08 +04:00
DEBUG ( 10 , ( " pid[%d] unlocked socket \n " , ( int ) getpid ( ) ) ) ;
2010-03-18 14:50:22 +03:00
2010-03-18 11:17:43 +03:00
return true ;
}
2010-04-01 04:40:30 +04:00
void smbd_unlock_socket ( struct smbd_server_connection * sconn )
{
if ( ! smbd_unlock_socket_internal ( sconn ) ) {
exit_server_cleanly ( " failed to unlock socket " ) ;
}
}
2007-11-05 22:12:56 +03:00
/* Accessor function for smb_read_error for smbd functions. */
2008-01-04 23:56:23 +03:00
/****************************************************************************
Send an smb to a fd .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-24 22:10:20 +04:00
bool srv_send_smb ( struct smbd_server_connection * sconn , char * buffer ,
2009-03-09 11:47:59 +03:00
bool do_signing , uint32_t seqnum ,
bool do_encrypt ,
struct smb_perfcount_data * pcd )
2008-01-04 23:56:23 +03:00
{
2009-02-09 10:10:34 +03:00
size_t len = 0 ;
2008-01-04 23:56:23 +03:00
size_t nwritten = 0 ;
ssize_t ret ;
char * buf_out = buffer ;
2010-03-18 11:23:48 +03:00
2010-08-24 22:10:20 +04:00
smbd_lock_socket ( sconn ) ;
2008-01-04 23:56:23 +03:00
2009-03-09 11:47:59 +03:00
if ( do_signing ) {
/* Sign the outgoing packet if required. */
2010-08-24 22:10:20 +04:00
srv_calculate_sign_mac ( sconn , buf_out , seqnum ) ;
2009-03-09 11:47:59 +03:00
}
2008-01-04 23:56:23 +03:00
if ( do_encrypt ) {
2011-08-05 19:00:42 +04:00
NTSTATUS status = srv_encrypt_buffer ( sconn , buffer , & buf_out ) ;
2008-01-04 23:56:23 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " send_smb: SMB encryption failed "
" on outgoing packet! Error %s \n " ,
nt_errstr ( status ) ) ) ;
2009-02-09 10:10:34 +03:00
goto out ;
2008-01-04 23:56:23 +03:00
}
}
len = smb_len ( buf_out ) + 4 ;
2010-08-24 22:10:20 +04:00
ret = write_data ( sconn - > sock , buf_out + nwritten , len - nwritten ) ;
2009-04-12 16:05:58 +04:00
if ( ret < = 0 ) {
2010-08-15 18:02:37 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
/*
* Try and give an error message saying what
* client failed .
*/
2010-09-28 12:38:20 +04:00
DEBUG ( 1 , ( " pid[%d] Error writing %d bytes to client %s. %d. (%s) \n " ,
2012-03-24 23:17:08 +04:00
( int ) getpid ( ) , ( int ) len ,
2010-08-24 22:10:20 +04:00
get_peer_addr ( sconn - > sock , addr , sizeof ( addr ) ) ,
2010-08-15 18:02:37 +04:00
( int ) ret , strerror ( errno ) ) ) ;
2011-08-05 18:52:25 +04:00
srv_free_enc_buffer ( sconn , buf_out ) ;
2009-04-12 16:05:58 +04:00
goto out ;
2008-01-04 23:56:23 +03:00
}
2009-02-09 10:10:34 +03:00
SMB_PERFCOUNT_SET_MSGLEN_OUT ( pcd , len ) ;
2011-08-05 18:52:25 +04:00
srv_free_enc_buffer ( sconn , buf_out ) ;
2009-02-09 10:10:34 +03:00
out :
SMB_PERFCOUNT_END ( pcd ) ;
2010-03-18 11:23:48 +03:00
2010-08-24 22:10:20 +04:00
smbd_unlock_socket ( sconn ) ;
2008-01-04 23:56:23 +03:00
return true ;
}
2007-12-27 04:12:36 +03:00
/*******************************************************************
Setup the word count and byte count for a smb message .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-01-04 23:56:23 +03:00
int srv_set_message ( char * buf ,
2007-12-27 04:12:36 +03:00
int num_words ,
int num_bytes ,
bool zero )
{
if ( zero & & ( num_words | | num_bytes ) ) {
memset ( buf + smb_size , ' \0 ' , num_words * 2 + num_bytes ) ;
}
SCVAL ( buf , smb_wct , num_words ) ;
SSVAL ( buf , smb_vwv + num_words * SIZEOFWORD , num_bytes ) ;
2008-01-04 23:56:23 +03:00
smb_setlen ( buf , ( smb_size + num_words * 2 + num_bytes - 4 ) ) ;
2007-12-27 04:12:36 +03:00
return ( smb_size + num_words * 2 + num_bytes ) ;
}
2011-08-05 18:44:01 +04:00
static bool valid_smb_header ( struct smbd_server_connection * sconn ,
const uint8_t * inbuf )
2007-12-27 04:12:36 +03:00
{
2011-08-05 18:49:20 +04:00
if ( is_encrypted_packet ( sconn , inbuf ) ) {
2008-01-04 23:56:23 +03:00
return true ;
2007-12-27 04:12:36 +03:00
}
2008-10-19 16:50:55 +04:00
/*
* This used to be ( strncmp ( smb_base ( inbuf ) , " \377 SMB " , 4 ) = = 0 )
* but it just looks weird to call strncmp for this one .
*/
return ( IVAL ( smb_base ( inbuf ) , 0 ) = = 0x424D53FF ) ;
2007-12-27 04:12:36 +03:00
}
2007-11-01 00:24:52 +03:00
/* Socket functions for smbd packet processing. */
2007-11-05 04:15:35 +03:00
static bool valid_packet_size ( size_t len )
2007-11-01 00:24:52 +03:00
{
/*
* A WRITEX with CAP_LARGE_WRITEX can be 64 k worth of data plus 65 bytes
* of header . Don ' t print the error if this fits . . . . JRA .
*/
if ( len > ( BUFFER_SIZE + LARGE_WRITEX_HDR_SIZE ) ) {
DEBUG ( 0 , ( " Invalid packet length! (%lu bytes). \n " ,
( unsigned long ) len ) ) ;
2008-05-28 20:31:42 +04:00
return false ;
2007-11-01 00:24:52 +03:00
}
return true ;
}
2008-01-26 00:27:59 +03:00
static NTSTATUS read_packet_remainder ( int fd , char * buffer ,
unsigned int timeout , ssize_t len )
2007-11-01 00:24:52 +03:00
{
2010-08-15 17:23:47 +04:00
NTSTATUS status ;
2008-01-26 00:21:38 +03:00
if ( len < = 0 ) {
2008-01-26 00:27:59 +03:00
return NT_STATUS_OK ;
2008-01-26 00:21:38 +03:00
}
2007-11-01 00:24:52 +03:00
2010-08-15 17:23:47 +04:00
status = read_fd_with_timeout ( fd , buffer , len , len , timeout , NULL ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
char addr [ INET6_ADDRSTRLEN ] ;
DEBUG ( 0 , ( " read_fd_with_timeout failed for client %s read "
" error = %s. \n " ,
get_peer_addr ( fd , addr , sizeof ( addr ) ) ,
nt_errstr ( status ) ) ) ;
}
return status ;
2007-11-01 00:24:52 +03:00
}
/****************************************************************************
Attempt a zerocopy writeX read . We know here that len > smb_size - 4
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/*
* Unfortunately , earlier versions of smbclient / libsmbclient
* don ' t send this " standard " writeX header . I ' ve fixed this
* for 3.2 but we ' ll use the old method with earlier versions .
* Windows and CIFSFS at least use this standard size . Not
* sure about MacOSX .
*/
# define STANDARD_WRITE_AND_X_HEADER_SIZE (smb_size - 4 + /* basic header */ \
( 2 * 14 ) + /* word count (including bcc) */ \
1 /* pad byte */ )
2008-01-26 01:12:04 +03:00
static NTSTATUS receive_smb_raw_talloc_partial_read ( TALLOC_CTX * mem_ctx ,
const char lenbuf [ 4 ] ,
2010-10-03 20:08:51 +04:00
struct smbd_server_connection * sconn ,
2011-04-14 16:05:43 +04:00
int sock ,
2010-10-03 20:08:51 +04:00
char * * buffer ,
2008-01-26 01:12:04 +03:00
unsigned int timeout ,
size_t * p_unread ,
size_t * len_ret )
2007-11-01 00:24:52 +03:00
{
/* Size of a WRITEX call (+4 byte len). */
char writeX_header [ 4 + STANDARD_WRITE_AND_X_HEADER_SIZE ] ;
ssize_t len = smb_len_large ( lenbuf ) ; /* Could be a UNIX large writeX. */
ssize_t toread ;
2008-01-26 01:12:04 +03:00
NTSTATUS status ;
2007-11-01 00:24:52 +03:00
2008-09-01 15:46:27 +04:00
memcpy ( writeX_header , lenbuf , 4 ) ;
2007-11-01 00:24:52 +03:00
2009-09-07 08:38:50 +04:00
status = read_fd_with_timeout (
2011-04-14 16:05:43 +04:00
sock , writeX_header + 4 ,
2008-01-26 01:12:04 +03:00
STANDARD_WRITE_AND_X_HEADER_SIZE ,
STANDARD_WRITE_AND_X_HEADER_SIZE ,
timeout , NULL ) ;
2007-11-01 00:24:52 +03:00
2008-01-26 01:12:04 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2010-08-15 17:23:47 +04:00
DEBUG ( 0 , ( " read_fd_with_timeout failed for client %s read "
2011-06-16 17:39:25 +04:00
" error = %s. \n " ,
tsocket_address_string ( sconn - > remote_address ,
talloc_tos ( ) ) ,
2010-08-15 17:23:47 +04:00
nt_errstr ( status ) ) ) ;
2008-01-26 01:12:04 +03:00
return status ;
2007-11-01 00:24:52 +03:00
}
/*
* Ok - now try and see if this is a possible
* valid writeX call .
*/
2010-10-03 20:08:51 +04:00
if ( is_valid_writeX_buffer ( sconn , ( uint8_t * ) writeX_header ) ) {
2007-11-01 00:24:52 +03:00
/*
* If the data offset is beyond what
* we ' ve read , drain the extra bytes .
*/
uint16_t doff = SVAL ( writeX_header , smb_vwv11 ) ;
ssize_t newlen ;
if ( doff > STANDARD_WRITE_AND_X_HEADER_SIZE ) {
size_t drain = doff - STANDARD_WRITE_AND_X_HEADER_SIZE ;
2011-04-14 16:05:43 +04:00
if ( drain_socket ( sock , drain ) ! = drain ) {
2007-11-01 00:24:52 +03:00
smb_panic ( " receive_smb_raw_talloc_partial_read: "
" failed to drain pending bytes " ) ;
}
} else {
doff = STANDARD_WRITE_AND_X_HEADER_SIZE ;
}
/* Spoof down the length and null out the bcc. */
set_message_bcc ( writeX_header , 0 ) ;
newlen = smb_len ( writeX_header ) ;
/* Copy the header we've written. */
2011-06-07 06:13:26 +04:00
* buffer = ( char * ) talloc_memdup ( mem_ctx ,
2007-11-01 00:24:52 +03:00
writeX_header ,
sizeof ( writeX_header ) ) ;
if ( * buffer = = NULL ) {
DEBUG ( 0 , ( " Could not allocate inbuf of length %d \n " ,
( int ) sizeof ( writeX_header ) ) ) ;
2008-01-26 01:12:04 +03:00
return NT_STATUS_NO_MEMORY ;
2007-11-01 00:24:52 +03:00
}
/* Work out the remaining bytes. */
* p_unread = len - STANDARD_WRITE_AND_X_HEADER_SIZE ;
2008-01-26 01:12:04 +03:00
* len_ret = newlen + 4 ;
return NT_STATUS_OK ;
2007-11-01 00:24:52 +03:00
}
if ( ! valid_packet_size ( len ) ) {
2008-01-26 01:12:04 +03:00
return NT_STATUS_INVALID_PARAMETER ;
2007-11-01 00:24:52 +03:00
}
/*
* Not a valid writeX call . Just do the standard
* talloc and return .
*/
2011-06-07 05:30:12 +04:00
* buffer = talloc_array ( mem_ctx , char , len + 4 ) ;
2007-11-01 00:24:52 +03:00
if ( * buffer = = NULL ) {
DEBUG ( 0 , ( " Could not allocate inbuf of length %d \n " ,
( int ) len + 4 ) ) ;
2008-01-26 01:12:04 +03:00
return NT_STATUS_NO_MEMORY ;
2007-11-01 00:24:52 +03:00
}
/* Copy in what we already read. */
memcpy ( * buffer ,
writeX_header ,
4 + STANDARD_WRITE_AND_X_HEADER_SIZE ) ;
toread = len - STANDARD_WRITE_AND_X_HEADER_SIZE ;
if ( toread > 0 ) {
2008-01-26 00:27:59 +03:00
status = read_packet_remainder (
2011-04-14 16:05:43 +04:00
sock ,
2010-10-03 20:08:51 +04:00
( * buffer ) + 4 + STANDARD_WRITE_AND_X_HEADER_SIZE ,
2008-01-26 00:27:59 +03:00
timeout , toread ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-05-20 23:09:48 +04:00
DEBUG ( 10 , ( " receive_smb_raw_talloc_partial_read: %s \n " ,
nt_errstr ( status ) ) ) ;
2008-01-26 01:12:04 +03:00
return status ;
2007-11-01 00:24:52 +03:00
}
}
2008-01-26 01:12:04 +03:00
* len_ret = len + 4 ;
return NT_STATUS_OK ;
2007-11-01 00:24:52 +03:00
}
2010-10-03 20:11:37 +04:00
static NTSTATUS receive_smb_raw_talloc ( TALLOC_CTX * mem_ctx ,
struct smbd_server_connection * sconn ,
2011-04-14 16:05:43 +04:00
int sock ,
2008-01-26 01:18:56 +03:00
char * * buffer , unsigned int timeout ,
size_t * p_unread , size_t * plen )
2007-11-01 00:24:52 +03:00
{
char lenbuf [ 4 ] ;
2008-01-25 23:24:48 +03:00
size_t len ;
2007-11-01 00:24:52 +03:00
int min_recv_size = lp_min_receive_file_size ( ) ;
2008-01-25 23:24:48 +03:00
NTSTATUS status ;
2007-11-01 00:24:52 +03:00
* p_unread = 0 ;
2011-04-14 16:05:43 +04:00
status = read_smb_length_return_keepalive ( sock , lenbuf , timeout ,
2010-10-03 20:11:37 +04:00
& len ) ;
2008-01-25 23:24:48 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-01-26 01:18:56 +03:00
return status ;
2007-11-01 00:24:52 +03:00
}
2009-02-10 10:43:08 +03:00
if ( CVAL ( lenbuf , 0 ) = = 0 & & min_recv_size & &
( smb_len_large ( lenbuf ) > /* Could be a UNIX large writeX. */
( min_recv_size + STANDARD_WRITE_AND_X_HEADER_SIZE ) ) & &
2010-10-03 20:11:37 +04:00
! srv_is_signing_active ( sconn ) & &
sconn - > smb1 . echo_handler . trusted_fde = = NULL ) {
2007-11-01 00:24:52 +03:00
2008-05-20 23:09:48 +04:00
return receive_smb_raw_talloc_partial_read (
2011-04-14 16:05:43 +04:00
mem_ctx , lenbuf , sconn , sock , buffer , timeout ,
2010-10-03 20:08:51 +04:00
p_unread , plen ) ;
2007-11-01 00:24:52 +03:00
}
if ( ! valid_packet_size ( len ) ) {
2008-01-26 01:18:56 +03:00
return NT_STATUS_INVALID_PARAMETER ;
2007-11-01 00:24:52 +03:00
}
/*
* The + 4 here can ' t wrap , we ' ve checked the length above already .
*/
2011-06-07 05:30:12 +04:00
* buffer = talloc_array ( mem_ctx , char , len + 4 ) ;
2007-11-01 00:24:52 +03:00
if ( * buffer = = NULL ) {
DEBUG ( 0 , ( " Could not allocate inbuf of length %d \n " ,
( int ) len + 4 ) ) ;
2008-01-26 01:18:56 +03:00
return NT_STATUS_NO_MEMORY ;
2007-11-01 00:24:52 +03:00
}
memcpy ( * buffer , lenbuf , sizeof ( lenbuf ) ) ;
2011-04-14 16:05:43 +04:00
status = read_packet_remainder ( sock , ( * buffer ) + 4 , timeout , len ) ;
2008-01-26 00:27:59 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2008-01-26 01:18:56 +03:00
return status ;
2007-11-01 00:24:52 +03:00
}
2008-01-26 01:18:56 +03:00
* plen = len + 4 ;
return NT_STATUS_OK ;
2007-11-01 00:24:52 +03:00
}
2010-10-03 20:13:39 +04:00
static NTSTATUS receive_smb_talloc ( TALLOC_CTX * mem_ctx ,
struct smbd_server_connection * sconn ,
2011-04-14 16:05:43 +04:00
int sock ,
2008-01-26 01:28:22 +03:00
char * * buffer , unsigned int timeout ,
size_t * p_unread , bool * p_encrypted ,
2009-03-09 11:47:59 +03:00
size_t * p_len ,
2010-03-18 17:36:19 +03:00
uint32_t * seqnum ,
bool trusted_channel )
2007-11-01 00:24:52 +03:00
{
2008-02-06 00:36:17 +03:00
size_t len = 0 ;
2008-01-26 01:18:56 +03:00
NTSTATUS status ;
2007-11-01 00:24:52 +03:00
2008-01-04 23:56:23 +03:00
* p_encrypted = false ;
2011-04-14 16:05:43 +04:00
status = receive_smb_raw_talloc ( mem_ctx , sconn , sock , buffer , timeout ,
2010-10-03 20:13:39 +04:00
p_unread , & len ) ;
2008-01-26 01:18:56 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
2011-11-04 20:34:48 +04:00
DEBUG ( NT_STATUS_EQUAL ( status , NT_STATUS_END_OF_FILE ) ? 5 : 1 ,
( " receive_smb_raw_talloc failed for client %s "
" read error = %s. \n " ,
tsocket_address_string ( sconn - > remote_address ,
talloc_tos ( ) ) ,
nt_errstr ( status ) ) ) ;
2008-01-26 01:28:22 +03:00
return status ;
2007-11-01 00:24:52 +03:00
}
2011-08-05 18:49:20 +04:00
if ( is_encrypted_packet ( sconn , ( uint8_t * ) * buffer ) ) {
2011-08-05 18:58:51 +04:00
status = srv_decrypt_buffer ( sconn , * buffer ) ;
2007-12-27 04:12:36 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " receive_smb_talloc: SMB decryption failed on "
" incoming packet! Error %s \n " ,
nt_errstr ( status ) ) ) ;
2008-01-26 01:28:22 +03:00
return status ;
2007-12-27 04:12:36 +03:00
}
2008-01-04 23:56:23 +03:00
* p_encrypted = true ;
2007-12-27 04:12:36 +03:00
}
2007-11-01 00:24:52 +03:00
/* Check the incoming SMB signature. */
2010-10-03 20:13:39 +04:00
if ( ! srv_check_sign_mac ( sconn , * buffer , seqnum , trusted_channel ) ) {
2007-11-01 00:24:52 +03:00
DEBUG ( 0 , ( " receive_smb: SMB Signature verification failed on "
" incoming packet! \n " ) ) ;
2008-01-26 01:28:22 +03:00
return NT_STATUS_INVALID_NETWORK_RESPONSE ;
2007-11-01 00:24:52 +03:00
}
2008-01-26 01:28:22 +03:00
* p_len = len ;
return NT_STATUS_OK ;
2007-11-01 00:24:52 +03:00
}
2007-07-05 20:26:27 +04:00
/*
* Initialize a struct smb_request from an inbuf
*/
2010-06-12 13:01:27 +04:00
static bool init_smb_request ( struct smb_request * req ,
struct smbd_server_connection * sconn ,
const uint8 * inbuf ,
2010-01-21 16:05:04 +03:00
size_t unread_bytes , bool encrypted ,
uint32_t seqnum )
2007-07-05 20:26:27 +04:00
{
2012-03-28 18:14:09 +04:00
struct smbXsrv_tcon * tcon ;
NTSTATUS status ;
NTTIME now ;
2007-08-15 23:43:26 +04:00
size_t req_size = smb_len ( inbuf ) + 4 ;
2012-04-11 18:54:17 +04:00
2007-08-15 23:43:26 +04:00
/* Ensure we have at least smb_size bytes. */
2007-08-15 23:25:38 +04:00
if ( req_size < smb_size ) {
DEBUG ( 0 , ( " init_smb_request: invalid request size %u \n " ,
( unsigned int ) req_size ) ) ;
2010-03-11 13:33:01 +03:00
return false ;
2007-08-15 23:25:38 +04:00
}
2012-04-11 18:54:17 +04:00
req - > request_time = timeval_current ( ) ;
2012-03-28 18:14:09 +04:00
now = timeval_to_nttime ( & req - > request_time ) ;
2012-04-11 18:54:17 +04:00
2008-11-03 00:33:20 +03:00
req - > cmd = CVAL ( inbuf , smb_com ) ;
2007-07-05 20:26:27 +04:00
req - > flags2 = SVAL ( inbuf , smb_flg2 ) ;
req - > smbpid = SVAL ( inbuf , smb_pid ) ;
2010-04-13 08:40:28 +04:00
req - > mid = ( uint64_t ) SVAL ( inbuf , smb_mid ) ;
2010-01-21 16:05:04 +03:00
req - > seqnum = seqnum ;
2007-07-05 20:26:27 +04:00
req - > vuid = SVAL ( inbuf , smb_uid ) ;
2007-07-23 13:36:09 +04:00
req - > tid = SVAL ( inbuf , smb_tid ) ;
req - > wct = CVAL ( inbuf , smb_wct ) ;
2012-02-23 13:50:46 +04:00
req - > vwv = ( const uint16_t * ) ( inbuf + smb_vwv ) ;
2008-11-01 18:24:42 +03:00
req - > buflen = smb_buflen ( inbuf ) ;
2011-05-05 21:41:59 +04:00
req - > buf = ( const uint8_t * ) smb_buf_const ( inbuf ) ;
2007-10-31 02:22:24 +03:00
req - > unread_bytes = unread_bytes ;
2008-01-04 23:56:23 +03:00
req - > encrypted = encrypted ;
2010-06-12 13:01:10 +04:00
req - > sconn = sconn ;
2012-03-28 18:14:09 +04:00
status = smb1srv_tcon_lookup ( sconn - > conn , req - > tid , now , & tcon ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
req - > conn = tcon - > compat ;
} else {
req - > conn = NULL ;
}
2008-10-09 18:55:56 +04:00
req - > chain_fsp = NULL ;
2010-04-09 09:15:55 +04:00
req - > smb2req = NULL ;
2012-03-01 05:04:08 +04:00
req - > priv_paths = NULL ;
2012-03-04 15:10:04 +04:00
req - > chain = NULL ;
2009-02-09 10:10:34 +03:00
smb_init_perfcount_data ( & req - > pcd ) ;
2007-10-31 02:22:24 +03:00
2007-08-17 03:53:51 +04:00
/* Ensure we have at least wct words and 2 bytes of bcc. */
2007-08-15 23:25:38 +04:00
if ( smb_size + req - > wct * 2 > req_size ) {
DEBUG ( 0 , ( " init_smb_request: invalid wct number %u (size %u) \n " ,
( unsigned int ) req - > wct ,
( unsigned int ) req_size ) ) ;
2010-03-11 13:33:01 +03:00
return false ;
2007-08-15 23:25:38 +04:00
}
2007-08-17 03:53:51 +04:00
/* Ensure bcc is correct. */
2011-05-05 21:41:59 +04:00
if ( ( ( const uint8_t * ) smb_buf_const ( inbuf ) ) + req - > buflen > inbuf + req_size ) {
2007-08-17 03:53:51 +04:00
DEBUG ( 0 , ( " init_smb_request: invalid bcc number %u "
" (wct = %u, size %u) \n " ,
2008-11-01 18:24:42 +03:00
( unsigned int ) req - > buflen ,
2007-08-17 03:53:51 +04:00
( unsigned int ) req - > wct ,
( unsigned int ) req_size ) ) ;
2010-03-11 13:33:01 +03:00
return false ;
2007-08-17 03:53:51 +04:00
}
2009-02-09 10:10:34 +03:00
2007-07-23 13:36:09 +04:00
req - > outbuf = NULL ;
2010-03-11 13:33:01 +03:00
return true ;
2007-07-05 20:26:27 +04:00
}
2009-01-08 17:38:47 +03:00
static void process_smb ( struct smbd_server_connection * conn ,
uint8_t * inbuf , size_t nread , size_t unread_bytes ,
2009-03-09 11:47:59 +03:00
uint32_t seqnum , bool encrypted ,
struct smb_perfcount_data * deferred_pcd ) ;
2009-01-08 17:38:47 +03:00
static void smbd_deferred_open_timer ( struct event_context * ev ,
struct timed_event * te ,
struct timeval _tval ,
void * private_data )
{
struct pending_message_list * msg = talloc_get_type ( private_data ,
struct pending_message_list ) ;
2011-12-12 14:11:55 +04:00
struct smbd_server_connection * sconn = msg - > sconn ;
2009-01-08 17:38:47 +03:00
TALLOC_CTX * mem_ctx = talloc_tos ( ) ;
2010-04-13 08:40:28 +04:00
uint64_t mid = ( uint64_t ) SVAL ( msg - > buf . data , smb_mid ) ;
2009-01-08 17:38:47 +03:00
uint8_t * inbuf ;
2009-01-10 15:02:43 +03:00
inbuf = ( uint8_t * ) talloc_memdup ( mem_ctx , msg - > buf . data ,
msg - > buf . length ) ;
2009-01-08 17:38:47 +03:00
if ( inbuf = = NULL ) {
exit_server ( " smbd_deferred_open_timer: talloc failed \n " ) ;
return ;
}
/* We leave this message on the queue so the open code can
know this is a retry . */
2010-04-13 08:40:28 +04:00
DEBUG ( 5 , ( " smbd_deferred_open_timer: trigger mid %llu. \n " ,
( unsigned long long ) mid ) ) ;
2009-10-01 16:32:36 +04:00
/* Mark the message as processed so this is not
* re - processed in error . */
msg - > processed = true ;
2009-01-08 17:38:47 +03:00
2011-12-12 14:11:55 +04:00
process_smb ( sconn , inbuf ,
2009-01-08 17:38:47 +03:00
msg - > buf . length , 0 ,
2009-03-09 11:47:59 +03:00
msg - > seqnum , msg - > encrypted , & msg - > pcd ) ;
2009-10-01 16:32:36 +04:00
/* If it's still there and was processed, remove it. */
2011-12-12 14:11:55 +04:00
msg = get_deferred_open_message_smb ( sconn , mid ) ;
2009-10-01 16:32:36 +04:00
if ( msg & & msg - > processed ) {
2011-12-12 14:11:55 +04:00
remove_deferred_open_message_smb ( sconn , mid ) ;
2009-10-01 16:32:36 +04:00
}
2009-01-08 17:38:47 +03:00
}
1998-09-23 05:48:45 +04:00
/****************************************************************************
2007-10-11 00:34:30 +04:00
Function to push a message onto the tail of a linked list of smb messages ready
for processing .
1998-09-23 05:48:45 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool push_queued_message ( struct smb_request * req ,
2005-09-30 21:13:37 +04:00
struct timeval request_time ,
struct timeval end_time ,
char * private_data , size_t private_len )
1998-09-23 05:48:45 +04:00
{
2007-08-27 16:04:09 +04:00
int msg_len = smb_len ( req - > inbuf ) + 4 ;
2005-09-30 21:13:37 +04:00
struct pending_message_list * msg ;
2011-06-07 05:44:43 +04:00
msg = talloc_zero ( NULL , struct pending_message_list ) ;
1998-09-23 05:48:45 +04:00
2003-07-16 22:06:27 +04:00
if ( msg = = NULL ) {
DEBUG ( 0 , ( " push_message: malloc fail (1) \n " ) ) ;
return False ;
}
2011-12-12 14:11:55 +04:00
msg - > sconn = req - > sconn ;
1998-09-23 05:48:45 +04:00
2007-08-27 16:04:09 +04:00
msg - > buf = data_blob_talloc ( msg , req - > inbuf , msg_len ) ;
2004-06-08 20:14:31 +04:00
if ( msg - > buf . data = = NULL ) {
2003-07-16 22:06:27 +04:00
DEBUG ( 0 , ( " push_message: malloc fail (2) \n " ) ) ;
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( msg ) ;
2003-07-16 22:06:27 +04:00
return False ;
}
1998-09-23 05:48:45 +04:00
2005-09-30 21:13:37 +04:00
msg - > request_time = request_time ;
2009-03-09 11:47:59 +03:00
msg - > seqnum = req - > seqnum ;
2008-01-04 23:56:23 +03:00
msg - > encrypted = req - > encrypted ;
2009-10-01 16:32:36 +04:00
msg - > processed = false ;
2009-02-09 10:10:34 +03:00
SMB_PERFCOUNT_DEFER_OP ( & req - > pcd , & msg - > pcd ) ;
2004-06-08 20:14:31 +04:00
2005-06-25 00:25:18 +04:00
if ( private_data ) {
2005-09-30 21:13:37 +04:00
msg - > private_data = data_blob_talloc ( msg , private_data ,
private_len ) ;
2004-06-08 20:14:31 +04:00
if ( msg - > private_data . data = = NULL ) {
DEBUG ( 0 , ( " push_message: malloc fail (3) \n " ) ) ;
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( msg ) ;
2005-06-06 19:21:09 +04:00
return False ;
2004-06-08 20:14:31 +04:00
}
}
1998-09-23 05:48:45 +04:00
2011-12-12 16:53:26 +04:00
msg - > te = tevent_add_timer ( msg - > sconn - > ev_ctx ,
msg ,
end_time ,
smbd_deferred_open_timer ,
msg ) ;
2009-01-08 17:38:47 +03:00
if ( ! msg - > te ) {
DEBUG ( 0 , ( " push_message: event_add_timed failed \n " ) ) ;
TALLOC_FREE ( msg ) ;
return false ;
}
2011-08-02 19:13:23 +04:00
DLIST_ADD_END ( req - > sconn - > deferred_open_queue , msg ,
struct pending_message_list * ) ;
1998-09-23 05:48:45 +04:00
2005-09-30 21:13:37 +04:00
DEBUG ( 10 , ( " push_message: pushed message length %u on "
" deferred_open_queue \n " , ( unsigned int ) msg_len ) ) ;
2004-06-08 20:14:31 +04:00
2003-07-16 22:06:27 +04:00
return True ;
1998-09-23 05:48:45 +04:00
}
2004-06-08 20:14:31 +04:00
/****************************************************************************
Function to delete a sharing violation open message by mid .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-08-02 18:53:33 +04:00
void remove_deferred_open_message_smb ( struct smbd_server_connection * sconn ,
uint64_t mid )
2004-06-08 20:14:31 +04:00
{
struct pending_message_list * pml ;
2011-08-02 18:53:33 +04:00
if ( sconn - > using_smb2 ) {
remove_deferred_open_message_smb2 ( sconn , mid ) ;
2010-04-10 06:26:34 +04:00
return ;
}
2011-08-02 19:13:23 +04:00
for ( pml = sconn - > deferred_open_queue ; pml ; pml = pml - > next ) {
2010-04-13 08:40:28 +04:00
if ( mid = = ( uint64_t ) SVAL ( pml - > buf . data , smb_mid ) ) {
2010-04-10 06:26:34 +04:00
DEBUG ( 10 , ( " remove_deferred_open_message_smb: "
2010-04-13 08:40:28 +04:00
" deleting mid %llu len %u \n " ,
( unsigned long long ) mid ,
2005-09-30 21:13:37 +04:00
( unsigned int ) pml - > buf . length ) ) ;
2011-08-02 19:13:23 +04:00
DLIST_REMOVE ( sconn - > deferred_open_queue , pml ) ;
2006-02-20 20:59:58 +03:00
TALLOC_FREE ( pml ) ;
2004-06-08 20:14:31 +04:00
return ;
}
}
}
/****************************************************************************
Move a sharing violation open retry message to the front of the list and
schedule it for immediate processing .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-06-30 00:56:26 +04:00
bool schedule_deferred_open_message_smb ( struct smbd_server_connection * sconn ,
2011-08-02 18:58:46 +04:00
uint64_t mid )
2004-06-08 20:14:31 +04:00
{
struct pending_message_list * pml ;
int i = 0 ;
2011-08-02 18:58:46 +04:00
if ( sconn - > using_smb2 ) {
2012-06-30 00:56:26 +04:00
return schedule_deferred_open_message_smb2 ( sconn , mid ) ;
2010-04-08 06:00:44 +04:00
}
2011-08-02 19:13:23 +04:00
for ( pml = sconn - > deferred_open_queue ; pml ; pml = pml - > next ) {
2010-04-13 08:40:28 +04:00
uint64_t msg_mid = ( uint64_t ) SVAL ( pml - > buf . data , smb_mid ) ;
2009-01-08 17:38:47 +03:00
2010-04-13 08:40:28 +04:00
DEBUG ( 10 , ( " schedule_deferred_open_message_smb: [%d] "
" msg_mid = %llu \n " ,
i + + ,
( unsigned long long ) msg_mid ) ) ;
2009-01-08 17:38:47 +03:00
2004-06-08 20:14:31 +04:00
if ( mid = = msg_mid ) {
2009-01-08 17:38:47 +03:00
struct timed_event * te ;
2009-10-01 16:32:36 +04:00
if ( pml - > processed ) {
/* A processed message should not be
* rescheduled . */
2010-04-10 06:26:34 +04:00
DEBUG ( 0 , ( " schedule_deferred_open_message_smb: LOGIC ERROR "
2010-04-13 08:40:28 +04:00
" message mid %llu was already processed \n " ,
( unsigned long long ) msg_mid ) ) ;
2009-10-01 16:32:36 +04:00
continue ;
}
2010-04-13 08:40:28 +04:00
DEBUG ( 10 , ( " schedule_deferred_open_message_smb: "
" scheduling mid %llu \n " ,
( unsigned long long ) mid ) ) ;
2009-01-08 17:38:47 +03:00
2011-12-12 16:53:26 +04:00
te = tevent_add_timer ( pml - > sconn - > ev_ctx ,
pml ,
timeval_zero ( ) ,
smbd_deferred_open_timer ,
pml ) ;
2009-01-08 17:38:47 +03:00
if ( ! te ) {
2010-04-10 06:26:34 +04:00
DEBUG ( 10 , ( " schedule_deferred_open_message_smb: "
2010-04-13 08:40:28 +04:00
" event_add_timed() failed, "
" skipping mid %llu \n " ,
( unsigned long long ) msg_mid ) ) ;
2009-01-08 17:38:47 +03:00
}
TALLOC_FREE ( pml - > te ) ;
pml - > te = te ;
2011-08-02 19:13:23 +04:00
DLIST_PROMOTE ( sconn - > deferred_open_queue , pml ) ;
2012-06-30 00:56:26 +04:00
return true ;
2004-06-08 20:14:31 +04:00
}
}
2010-04-13 08:40:28 +04:00
DEBUG ( 10 , ( " schedule_deferred_open_message_smb: failed to "
" find message mid %llu \n " ,
( unsigned long long ) mid ) ) ;
2012-06-30 00:56:26 +04:00
return false ;
2004-06-08 20:14:31 +04:00
}
/****************************************************************************
2009-10-01 16:32:36 +04:00
Return true if this mid is on the deferred queue and was not yet processed .
2004-06-08 20:14:31 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-08-02 19:05:33 +04:00
bool open_was_deferred ( struct smbd_server_connection * sconn , uint64_t mid )
2004-06-08 20:14:31 +04:00
{
struct pending_message_list * pml ;
2004-06-26 05:04:02 +04:00
2011-08-02 19:05:33 +04:00
if ( sconn - > using_smb2 ) {
return open_was_deferred_smb2 ( sconn , mid ) ;
2010-04-10 06:26:34 +04:00
}
2011-08-02 19:13:23 +04:00
for ( pml = sconn - > deferred_open_queue ; pml ; pml = pml - > next ) {
2010-04-13 08:40:28 +04:00
if ( ( ( uint64_t ) SVAL ( pml - > buf . data , smb_mid ) ) = = mid & & ! pml - > processed ) {
2004-06-08 20:14:31 +04:00
return True ;
}
}
return False ;
}
/****************************************************************************
Return the message queued by this mid .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-08-02 19:07:25 +04:00
static struct pending_message_list * get_deferred_open_message_smb (
struct smbd_server_connection * sconn , uint64_t mid )
2004-06-08 20:14:31 +04:00
{
struct pending_message_list * pml ;
2004-06-26 05:04:02 +04:00
2011-08-02 19:13:23 +04:00
for ( pml = sconn - > deferred_open_queue ; pml ; pml = pml - > next ) {
2010-04-13 08:40:28 +04:00
if ( ( ( uint64_t ) SVAL ( pml - > buf . data , smb_mid ) ) = = mid ) {
2004-06-08 20:14:31 +04:00
return pml ;
}
}
return NULL ;
}
2010-04-10 06:26:34 +04:00
/****************************************************************************
Get the state data queued by this mid .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-04-23 10:52:19 +04:00
bool get_deferred_open_message_state ( struct smb_request * smbreq ,
2010-04-10 06:26:34 +04:00
struct timeval * p_request_time ,
void * * pp_state )
{
struct pending_message_list * pml ;
2011-12-12 14:11:55 +04:00
if ( smbreq - > sconn - > using_smb2 ) {
2010-04-23 10:52:19 +04:00
return get_deferred_open_message_state_smb2 ( smbreq - > smb2req ,
2010-04-10 06:26:34 +04:00
p_request_time ,
pp_state ) ;
}
2011-08-02 19:07:25 +04:00
pml = get_deferred_open_message_smb ( smbreq - > sconn , smbreq - > mid ) ;
2010-04-10 06:26:34 +04:00
if ( ! pml ) {
return false ;
}
if ( p_request_time ) {
* p_request_time = pml - > request_time ;
}
if ( pp_state ) {
* pp_state = ( void * ) pml - > private_data . data ;
}
return true ;
}
2004-06-08 20:14:31 +04:00
/****************************************************************************
2005-09-30 21:13:37 +04:00
Function to push a deferred open smb message onto a linked list of local smb
messages ready for processing .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-04-10 06:26:34 +04:00
bool push_deferred_open_message_smb ( struct smb_request * req ,
2005-09-30 21:13:37 +04:00
struct timeval request_time ,
struct timeval timeout ,
2010-04-24 00:10:15 +04:00
struct file_id id ,
2005-09-30 21:13:37 +04:00
char * private_data , size_t priv_len )
{
struct timeval end_time ;
2010-04-10 06:26:34 +04:00
if ( req - > smb2req ) {
2010-04-23 10:52:19 +04:00
return push_deferred_open_message_smb2 ( req - > smb2req ,
2010-04-10 06:26:34 +04:00
request_time ,
timeout ,
2010-04-24 00:10:15 +04:00
id ,
2010-04-10 06:26:34 +04:00
private_data ,
priv_len ) ;
}
2007-10-31 02:22:24 +03:00
if ( req - > unread_bytes ) {
2010-04-10 06:26:34 +04:00
DEBUG ( 0 , ( " push_deferred_open_message_smb: logic error ! "
2007-10-31 02:22:24 +03:00
" unread_bytes = %u \n " ,
( unsigned int ) req - > unread_bytes ) ) ;
2010-04-10 06:26:34 +04:00
smb_panic ( " push_deferred_open_message_smb: "
2007-10-31 02:22:24 +03:00
" logic error unread_bytes != 0 " ) ;
}
2005-09-30 21:13:37 +04:00
end_time = timeval_sum ( & request_time , & timeout ) ;
2010-04-13 08:40:28 +04:00
DEBUG ( 10 , ( " push_deferred_open_message_smb: pushing message "
" len %u mid %llu timeout time [%u.%06u] \n " ,
( unsigned int ) smb_len ( req - > inbuf ) + 4 ,
( unsigned long long ) req - > mid ,
( unsigned int ) end_time . tv_sec ,
( unsigned int ) end_time . tv_usec ) ) ;
2005-09-30 21:13:37 +04:00
2007-08-27 16:04:09 +04:00
return push_queued_message ( req , request_time , end_time ,
2005-09-30 21:13:37 +04:00
private_data , priv_len ) ;
}
2009-01-22 01:24:18 +03:00
static void smbd_sig_term_handler ( struct tevent_context * ev ,
struct tevent_signal * se ,
int signum ,
int count ,
void * siginfo ,
void * private_data )
{
exit_server_cleanly ( " termination signal " ) ;
}
2011-12-13 16:55:02 +04:00
void smbd_setup_sig_term_handler ( struct smbd_server_connection * sconn )
2009-01-22 01:24:18 +03:00
{
struct tevent_signal * se ;
2011-12-13 16:55:02 +04:00
se = tevent_add_signal ( sconn - > ev_ctx ,
sconn ,
2009-01-22 01:24:18 +03:00
SIGTERM , 0 ,
smbd_sig_term_handler ,
2011-12-13 16:55:02 +04:00
sconn ) ;
2009-01-22 01:24:18 +03:00
if ( ! se ) {
exit_server ( " failed to setup SIGTERM handler " ) ;
}
}
static void smbd_sig_hup_handler ( struct tevent_context * ev ,
struct tevent_signal * se ,
int signum ,
int count ,
void * siginfo ,
void * private_data )
{
2011-12-13 16:55:02 +04:00
struct smbd_server_connection * sconn =
talloc_get_type_abort ( private_data ,
struct smbd_server_connection ) ;
2009-01-22 01:24:18 +03:00
change_to_root_user ( ) ;
DEBUG ( 1 , ( " Reloading services after SIGHUP \n " ) ) ;
2011-12-14 16:25:20 +04:00
reload_services ( sconn , conn_snum_used , false ) ;
2009-01-22 01:24:18 +03:00
}
2011-12-13 16:55:02 +04:00
void smbd_setup_sig_hup_handler ( struct smbd_server_connection * sconn )
2009-01-22 01:24:18 +03:00
{
struct tevent_signal * se ;
2011-12-13 16:55:02 +04:00
se = tevent_add_signal ( sconn - > ev_ctx ,
sconn ,
SIGHUP , 0 ,
smbd_sig_hup_handler ,
sconn ) ;
2009-01-22 01:24:18 +03:00
if ( ! se ) {
exit_server ( " failed to setup SIGHUP handler " ) ;
}
}
2011-12-14 15:39:36 +04:00
static void smbd_conf_updated ( struct messaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
struct smbd_server_connection * sconn =
talloc_get_type_abort ( private_data ,
struct smbd_server_connection ) ;
DEBUG ( 10 , ( " smbd_conf_updated: Got message saying smb.conf was "
" updated. Reloading. \n " ) ) ;
change_to_root_user ( ) ;
2011-12-14 16:25:20 +04:00
reload_services ( sconn , conn_snum_used , false ) ;
2011-12-14 15:39:36 +04:00
}
2006-04-10 19:33:04 +04:00
/*
* Only allow 5 outstanding trans requests . We ' re allocating memory , so
* prevent a DoS .
*/
1998-09-23 05:48:45 +04:00
2010-04-13 08:40:28 +04:00
NTSTATUS allow_new_trans ( struct trans_state * list , uint64_t mid )
1998-08-17 17:11:34 +04:00
{
2006-04-10 19:33:04 +04:00
int count = 0 ;
for ( ; list ! = NULL ; list = list - > next ) {
1998-08-17 17:11:34 +04:00
2006-04-10 19:33:04 +04:00
if ( list - > mid = = mid ) {
return NT_STATUS_INVALID_PARAMETER ;
}
count + = 1 ;
}
if ( count > 5 ) {
return NT_STATUS_INSUFFICIENT_RESOURCES ;
}
1998-08-17 17:11:34 +04:00
2006-04-10 19:33:04 +04:00
return NT_STATUS_OK ;
1998-08-17 17:11:34 +04:00
}
/*
These flags determine some of the permissions required to do an operation
Note that I don ' t set NEED_WRITE on some write operations because they
are used by some brain - dead clients when printing , and I don ' t want to
force write permissions on print services .
*/
# define AS_USER (1<<0)
2006-06-20 06:38:28 +04:00
# define NEED_WRITE (1<<1) /* Must be paired with AS_USER */
1998-08-17 17:11:34 +04:00
# define TIME_INIT (1<<2)
2006-06-20 06:38:28 +04:00
# define CAN_IPC (1<<3) /* Must be paired with AS_USER */
# define AS_GUEST (1<<5) /* Must *NOT* be paired with AS_USER */
2005-09-30 21:13:37 +04:00
# define DO_CHDIR (1<<6)
1998-08-17 17:11:34 +04:00
/*
define a list of possible SMB messages and their corresponding
functions . Any message that has a NULL function is unimplemented -
please feel free to contribute implementations !
*/
2003-07-16 22:06:27 +04:00
static const struct smb_message_struct {
const char * name ;
2008-10-19 17:17:12 +04:00
void ( * fn ) ( struct smb_request * req ) ;
2003-07-16 22:06:27 +04:00
int flags ;
} smb_messages [ 256 ] = {
2001-01-24 22:04:56 +03:00
2007-08-27 16:04:09 +04:00
/* 0x00 */ { " SMBmkdir " , reply_mkdir , AS_USER | NEED_WRITE } ,
/* 0x01 */ { " SMBrmdir " , reply_rmdir , AS_USER | NEED_WRITE } ,
/* 0x02 */ { " SMBopen " , reply_open , AS_USER } ,
/* 0x03 */ { " SMBcreate " , reply_mknew , AS_USER } ,
/* 0x04 */ { " SMBclose " , reply_close , AS_USER | CAN_IPC } ,
/* 0x05 */ { " SMBflush " , reply_flush , AS_USER } ,
/* 0x06 */ { " SMBunlink " , reply_unlink , AS_USER | NEED_WRITE } ,
/* 0x07 */ { " SMBmv " , reply_mv , AS_USER | NEED_WRITE } ,
/* 0x08 */ { " SMBgetatr " , reply_getatr , AS_USER } ,
/* 0x09 */ { " SMBsetatr " , reply_setatr , AS_USER | NEED_WRITE } ,
/* 0x0a */ { " SMBread " , reply_read , AS_USER } ,
/* 0x0b */ { " SMBwrite " , reply_write , AS_USER | CAN_IPC } ,
/* 0x0c */ { " SMBlock " , reply_lock , AS_USER } ,
/* 0x0d */ { " SMBunlock " , reply_unlock , AS_USER } ,
/* 0x0e */ { " SMBctemp " , reply_ctemp , AS_USER } ,
/* 0x0f */ { " SMBmknew " , reply_mknew , AS_USER } ,
/* 0x10 */ { " SMBcheckpath " , reply_checkpath , AS_USER } ,
/* 0x11 */ { " SMBexit " , reply_exit , DO_CHDIR } ,
/* 0x12 */ { " SMBlseek " , reply_lseek , AS_USER } ,
/* 0x13 */ { " SMBlockread " , reply_lockread , AS_USER } ,
/* 0x14 */ { " SMBwriteunlock " , reply_writeunlock , AS_USER } ,
/* 0x15 */ { NULL , NULL , 0 } ,
/* 0x16 */ { NULL , NULL , 0 } ,
/* 0x17 */ { NULL , NULL , 0 } ,
/* 0x18 */ { NULL , NULL , 0 } ,
/* 0x19 */ { NULL , NULL , 0 } ,
/* 0x1a */ { " SMBreadbraw " , reply_readbraw , AS_USER } ,
/* 0x1b */ { " SMBreadBmpx " , reply_readbmpx , AS_USER } ,
/* 0x1c */ { " SMBreadBs " , reply_readbs , AS_USER } ,
/* 0x1d */ { " SMBwritebraw " , reply_writebraw , AS_USER } ,
/* 0x1e */ { " SMBwriteBmpx " , reply_writebmpx , AS_USER } ,
/* 0x1f */ { " SMBwriteBs " , reply_writebs , AS_USER } ,
/* 0x20 */ { " SMBwritec " , NULL , 0 } ,
/* 0x21 */ { NULL , NULL , 0 } ,
/* 0x22 */ { " SMBsetattrE " , reply_setattrE , AS_USER | NEED_WRITE } ,
/* 0x23 */ { " SMBgetattrE " , reply_getattrE , AS_USER } ,
/* 0x24 */ { " SMBlockingX " , reply_lockingX , AS_USER } ,
/* 0x25 */ { " SMBtrans " , reply_trans , AS_USER | CAN_IPC } ,
/* 0x26 */ { " SMBtranss " , reply_transs , AS_USER | CAN_IPC } ,
/* 0x27 */ { " SMBioctl " , reply_ioctl , 0 } ,
/* 0x28 */ { " SMBioctls " , NULL , AS_USER } ,
/* 0x29 */ { " SMBcopy " , reply_copy , AS_USER | NEED_WRITE } ,
/* 0x2a */ { " SMBmove " , NULL , AS_USER | NEED_WRITE } ,
/* 0x2b */ { " SMBecho " , reply_echo , 0 } ,
/* 0x2c */ { " SMBwriteclose " , reply_writeclose , AS_USER } ,
/* 0x2d */ { " SMBopenX " , reply_open_and_X , AS_USER | CAN_IPC } ,
/* 0x2e */ { " SMBreadX " , reply_read_and_X , AS_USER | CAN_IPC } ,
/* 0x2f */ { " SMBwriteX " , reply_write_and_X , AS_USER | CAN_IPC } ,
/* 0x30 */ { NULL , NULL , 0 } ,
/* 0x31 */ { NULL , NULL , 0 } ,
/* 0x32 */ { " SMBtrans2 " , reply_trans2 , AS_USER | CAN_IPC } ,
2009-03-23 13:44:00 +03:00
/* 0x33 */ { " SMBtranss2 " , reply_transs2 , AS_USER | CAN_IPC } ,
2007-08-27 16:04:09 +04:00
/* 0x34 */ { " SMBfindclose " , reply_findclose , AS_USER } ,
/* 0x35 */ { " SMBfindnclose " , reply_findnclose , AS_USER } ,
/* 0x36 */ { NULL , NULL , 0 } ,
/* 0x37 */ { NULL , NULL , 0 } ,
/* 0x38 */ { NULL , NULL , 0 } ,
/* 0x39 */ { NULL , NULL , 0 } ,
/* 0x3a */ { NULL , NULL , 0 } ,
/* 0x3b */ { NULL , NULL , 0 } ,
/* 0x3c */ { NULL , NULL , 0 } ,
/* 0x3d */ { NULL , NULL , 0 } ,
/* 0x3e */ { NULL , NULL , 0 } ,
/* 0x3f */ { NULL , NULL , 0 } ,
/* 0x40 */ { NULL , NULL , 0 } ,
/* 0x41 */ { NULL , NULL , 0 } ,
/* 0x42 */ { NULL , NULL , 0 } ,
/* 0x43 */ { NULL , NULL , 0 } ,
/* 0x44 */ { NULL , NULL , 0 } ,
/* 0x45 */ { NULL , NULL , 0 } ,
/* 0x46 */ { NULL , NULL , 0 } ,
/* 0x47 */ { NULL , NULL , 0 } ,
/* 0x48 */ { NULL , NULL , 0 } ,
/* 0x49 */ { NULL , NULL , 0 } ,
/* 0x4a */ { NULL , NULL , 0 } ,
/* 0x4b */ { NULL , NULL , 0 } ,
/* 0x4c */ { NULL , NULL , 0 } ,
/* 0x4d */ { NULL , NULL , 0 } ,
/* 0x4e */ { NULL , NULL , 0 } ,
/* 0x4f */ { NULL , NULL , 0 } ,
/* 0x50 */ { NULL , NULL , 0 } ,
/* 0x51 */ { NULL , NULL , 0 } ,
/* 0x52 */ { NULL , NULL , 0 } ,
/* 0x53 */ { NULL , NULL , 0 } ,
/* 0x54 */ { NULL , NULL , 0 } ,
/* 0x55 */ { NULL , NULL , 0 } ,
/* 0x56 */ { NULL , NULL , 0 } ,
/* 0x57 */ { NULL , NULL , 0 } ,
/* 0x58 */ { NULL , NULL , 0 } ,
/* 0x59 */ { NULL , NULL , 0 } ,
/* 0x5a */ { NULL , NULL , 0 } ,
/* 0x5b */ { NULL , NULL , 0 } ,
/* 0x5c */ { NULL , NULL , 0 } ,
/* 0x5d */ { NULL , NULL , 0 } ,
/* 0x5e */ { NULL , NULL , 0 } ,
/* 0x5f */ { NULL , NULL , 0 } ,
/* 0x60 */ { NULL , NULL , 0 } ,
/* 0x61 */ { NULL , NULL , 0 } ,
/* 0x62 */ { NULL , NULL , 0 } ,
/* 0x63 */ { NULL , NULL , 0 } ,
/* 0x64 */ { NULL , NULL , 0 } ,
/* 0x65 */ { NULL , NULL , 0 } ,
/* 0x66 */ { NULL , NULL , 0 } ,
/* 0x67 */ { NULL , NULL , 0 } ,
/* 0x68 */ { NULL , NULL , 0 } ,
/* 0x69 */ { NULL , NULL , 0 } ,
/* 0x6a */ { NULL , NULL , 0 } ,
/* 0x6b */ { NULL , NULL , 0 } ,
/* 0x6c */ { NULL , NULL , 0 } ,
/* 0x6d */ { NULL , NULL , 0 } ,
/* 0x6e */ { NULL , NULL , 0 } ,
/* 0x6f */ { NULL , NULL , 0 } ,
/* 0x70 */ { " SMBtcon " , reply_tcon , 0 } ,
/* 0x71 */ { " SMBtdis " , reply_tdis , DO_CHDIR } ,
/* 0x72 */ { " SMBnegprot " , reply_negprot , 0 } ,
/* 0x73 */ { " SMBsesssetupX " , reply_sesssetup_and_X , 0 } ,
/* 0x74 */ { " SMBulogoffX " , reply_ulogoffX , 0 } , /* ulogoff doesn't give a valid TID */
/* 0x75 */ { " SMBtconX " , reply_tcon_and_X , 0 } ,
/* 0x76 */ { NULL , NULL , 0 } ,
/* 0x77 */ { NULL , NULL , 0 } ,
/* 0x78 */ { NULL , NULL , 0 } ,
/* 0x79 */ { NULL , NULL , 0 } ,
/* 0x7a */ { NULL , NULL , 0 } ,
/* 0x7b */ { NULL , NULL , 0 } ,
/* 0x7c */ { NULL , NULL , 0 } ,
/* 0x7d */ { NULL , NULL , 0 } ,
/* 0x7e */ { NULL , NULL , 0 } ,
/* 0x7f */ { NULL , NULL , 0 } ,
/* 0x80 */ { " SMBdskattr " , reply_dskattr , AS_USER } ,
/* 0x81 */ { " SMBsearch " , reply_search , AS_USER } ,
/* 0x82 */ { " SMBffirst " , reply_search , AS_USER } ,
/* 0x83 */ { " SMBfunique " , reply_search , AS_USER } ,
/* 0x84 */ { " SMBfclose " , reply_fclose , AS_USER } ,
/* 0x85 */ { NULL , NULL , 0 } ,
/* 0x86 */ { NULL , NULL , 0 } ,
/* 0x87 */ { NULL , NULL , 0 } ,
/* 0x88 */ { NULL , NULL , 0 } ,
/* 0x89 */ { NULL , NULL , 0 } ,
/* 0x8a */ { NULL , NULL , 0 } ,
/* 0x8b */ { NULL , NULL , 0 } ,
/* 0x8c */ { NULL , NULL , 0 } ,
/* 0x8d */ { NULL , NULL , 0 } ,
/* 0x8e */ { NULL , NULL , 0 } ,
/* 0x8f */ { NULL , NULL , 0 } ,
/* 0x90 */ { NULL , NULL , 0 } ,
/* 0x91 */ { NULL , NULL , 0 } ,
/* 0x92 */ { NULL , NULL , 0 } ,
/* 0x93 */ { NULL , NULL , 0 } ,
/* 0x94 */ { NULL , NULL , 0 } ,
/* 0x95 */ { NULL , NULL , 0 } ,
/* 0x96 */ { NULL , NULL , 0 } ,
/* 0x97 */ { NULL , NULL , 0 } ,
/* 0x98 */ { NULL , NULL , 0 } ,
/* 0x99 */ { NULL , NULL , 0 } ,
/* 0x9a */ { NULL , NULL , 0 } ,
/* 0x9b */ { NULL , NULL , 0 } ,
/* 0x9c */ { NULL , NULL , 0 } ,
/* 0x9d */ { NULL , NULL , 0 } ,
/* 0x9e */ { NULL , NULL , 0 } ,
/* 0x9f */ { NULL , NULL , 0 } ,
/* 0xa0 */ { " SMBnttrans " , reply_nttrans , AS_USER | CAN_IPC } ,
/* 0xa1 */ { " SMBnttranss " , reply_nttranss , AS_USER | CAN_IPC } ,
/* 0xa2 */ { " SMBntcreateX " , reply_ntcreate_and_X , AS_USER | CAN_IPC } ,
/* 0xa3 */ { NULL , NULL , 0 } ,
/* 0xa4 */ { " SMBntcancel " , reply_ntcancel , 0 } ,
/* 0xa5 */ { " SMBntrename " , reply_ntrename , AS_USER | NEED_WRITE } ,
/* 0xa6 */ { NULL , NULL , 0 } ,
/* 0xa7 */ { NULL , NULL , 0 } ,
/* 0xa8 */ { NULL , NULL , 0 } ,
/* 0xa9 */ { NULL , NULL , 0 } ,
/* 0xaa */ { NULL , NULL , 0 } ,
/* 0xab */ { NULL , NULL , 0 } ,
/* 0xac */ { NULL , NULL , 0 } ,
/* 0xad */ { NULL , NULL , 0 } ,
/* 0xae */ { NULL , NULL , 0 } ,
/* 0xaf */ { NULL , NULL , 0 } ,
/* 0xb0 */ { NULL , NULL , 0 } ,
/* 0xb1 */ { NULL , NULL , 0 } ,
/* 0xb2 */ { NULL , NULL , 0 } ,
/* 0xb3 */ { NULL , NULL , 0 } ,
/* 0xb4 */ { NULL , NULL , 0 } ,
/* 0xb5 */ { NULL , NULL , 0 } ,
/* 0xb6 */ { NULL , NULL , 0 } ,
/* 0xb7 */ { NULL , NULL , 0 } ,
/* 0xb8 */ { NULL , NULL , 0 } ,
/* 0xb9 */ { NULL , NULL , 0 } ,
/* 0xba */ { NULL , NULL , 0 } ,
/* 0xbb */ { NULL , NULL , 0 } ,
/* 0xbc */ { NULL , NULL , 0 } ,
/* 0xbd */ { NULL , NULL , 0 } ,
/* 0xbe */ { NULL , NULL , 0 } ,
/* 0xbf */ { NULL , NULL , 0 } ,
/* 0xc0 */ { " SMBsplopen " , reply_printopen , AS_USER } ,
/* 0xc1 */ { " SMBsplwr " , reply_printwrite , AS_USER } ,
/* 0xc2 */ { " SMBsplclose " , reply_printclose , AS_USER } ,
/* 0xc3 */ { " SMBsplretq " , reply_printqueue , AS_USER } ,
/* 0xc4 */ { NULL , NULL , 0 } ,
/* 0xc5 */ { NULL , NULL , 0 } ,
/* 0xc6 */ { NULL , NULL , 0 } ,
/* 0xc7 */ { NULL , NULL , 0 } ,
/* 0xc8 */ { NULL , NULL , 0 } ,
/* 0xc9 */ { NULL , NULL , 0 } ,
/* 0xca */ { NULL , NULL , 0 } ,
/* 0xcb */ { NULL , NULL , 0 } ,
/* 0xcc */ { NULL , NULL , 0 } ,
/* 0xcd */ { NULL , NULL , 0 } ,
/* 0xce */ { NULL , NULL , 0 } ,
/* 0xcf */ { NULL , NULL , 0 } ,
/* 0xd0 */ { " SMBsends " , reply_sends , AS_GUEST } ,
/* 0xd1 */ { " SMBsendb " , NULL , AS_GUEST } ,
/* 0xd2 */ { " SMBfwdname " , NULL , AS_GUEST } ,
/* 0xd3 */ { " SMBcancelf " , NULL , AS_GUEST } ,
/* 0xd4 */ { " SMBgetmac " , NULL , AS_GUEST } ,
/* 0xd5 */ { " SMBsendstrt " , reply_sendstrt , AS_GUEST } ,
/* 0xd6 */ { " SMBsendend " , reply_sendend , AS_GUEST } ,
/* 0xd7 */ { " SMBsendtxt " , reply_sendtxt , AS_GUEST } ,
/* 0xd8 */ { NULL , NULL , 0 } ,
/* 0xd9 */ { NULL , NULL , 0 } ,
/* 0xda */ { NULL , NULL , 0 } ,
/* 0xdb */ { NULL , NULL , 0 } ,
/* 0xdc */ { NULL , NULL , 0 } ,
/* 0xdd */ { NULL , NULL , 0 } ,
/* 0xde */ { NULL , NULL , 0 } ,
/* 0xdf */ { NULL , NULL , 0 } ,
/* 0xe0 */ { NULL , NULL , 0 } ,
/* 0xe1 */ { NULL , NULL , 0 } ,
/* 0xe2 */ { NULL , NULL , 0 } ,
/* 0xe3 */ { NULL , NULL , 0 } ,
/* 0xe4 */ { NULL , NULL , 0 } ,
/* 0xe5 */ { NULL , NULL , 0 } ,
/* 0xe6 */ { NULL , NULL , 0 } ,
/* 0xe7 */ { NULL , NULL , 0 } ,
/* 0xe8 */ { NULL , NULL , 0 } ,
/* 0xe9 */ { NULL , NULL , 0 } ,
/* 0xea */ { NULL , NULL , 0 } ,
/* 0xeb */ { NULL , NULL , 0 } ,
/* 0xec */ { NULL , NULL , 0 } ,
/* 0xed */ { NULL , NULL , 0 } ,
/* 0xee */ { NULL , NULL , 0 } ,
/* 0xef */ { NULL , NULL , 0 } ,
/* 0xf0 */ { NULL , NULL , 0 } ,
/* 0xf1 */ { NULL , NULL , 0 } ,
/* 0xf2 */ { NULL , NULL , 0 } ,
/* 0xf3 */ { NULL , NULL , 0 } ,
/* 0xf4 */ { NULL , NULL , 0 } ,
/* 0xf5 */ { NULL , NULL , 0 } ,
/* 0xf6 */ { NULL , NULL , 0 } ,
/* 0xf7 */ { NULL , NULL , 0 } ,
/* 0xf8 */ { NULL , NULL , 0 } ,
/* 0xf9 */ { NULL , NULL , 0 } ,
/* 0xfa */ { NULL , NULL , 0 } ,
/* 0xfb */ { NULL , NULL , 0 } ,
/* 0xfc */ { NULL , NULL , 0 } ,
/* 0xfd */ { NULL , NULL , 0 } ,
/* 0xfe */ { NULL , NULL , 0 } ,
/* 0xff */ { NULL , NULL , 0 }
2001-01-24 22:04:56 +03:00
} ;
1998-08-17 17:11:34 +04:00
2007-07-23 13:36:09 +04:00
/*******************************************************************
allocate and initialize a reply packet
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-12-19 20:07:44 +03:00
static bool create_outbuf ( TALLOC_CTX * mem_ctx , struct smb_request * req ,
const char * inbuf , char * * outbuf , uint8_t num_words ,
uint32_t num_bytes )
2007-07-23 13:36:09 +04:00
{
2007-08-12 16:15:32 +04:00
/*
* Protect against integer wrap
*/
if ( ( num_bytes > 0xffffff )
| | ( ( num_bytes + smb_size + num_words * 2 ) > 0xffffff ) ) {
char * msg ;
2008-04-02 17:54:49 +04:00
if ( asprintf ( & msg , " num_bytes too large: %u " ,
( unsigned ) num_bytes ) = = - 1 ) {
2011-05-05 21:41:59 +04:00
msg = discard_const_p ( char , " num_bytes too large " ) ;
2008-04-02 17:54:49 +04:00
}
2007-08-12 16:15:32 +04:00
smb_panic ( msg ) ;
}
2011-06-07 05:30:12 +04:00
* outbuf = talloc_array ( mem_ctx , char ,
2008-04-02 17:34:29 +04:00
smb_size + num_words * 2 + num_bytes ) ;
if ( * outbuf = = NULL ) {
return false ;
2007-07-23 13:36:09 +04:00
}
2008-12-19 20:07:44 +03:00
construct_reply_common ( req , inbuf , * outbuf ) ;
2008-04-02 17:34:29 +04:00
srv_set_message ( * outbuf , num_words , num_bytes , false ) ;
2007-07-23 13:36:09 +04:00
/*
* Zero out the word area , the caller has to take care of the bcc area
* himself
*/
if ( num_words ! = 0 ) {
2008-04-02 17:34:29 +04:00
memset ( * outbuf + smb_vwv0 , 0 , num_words * 2 ) ;
2007-07-23 13:36:09 +04:00
}
2008-04-02 17:34:29 +04:00
return true ;
}
void reply_outbuf ( struct smb_request * req , uint8 num_words , uint32 num_bytes )
{
char * outbuf ;
2011-05-05 21:41:59 +04:00
if ( ! create_outbuf ( req , req , ( const char * ) req - > inbuf , & outbuf , num_words ,
2008-04-02 17:34:29 +04:00
num_bytes ) ) {
smb_panic ( " could not allocate output buffer \n " ) ;
}
req - > outbuf = ( uint8_t * ) outbuf ;
2007-07-23 13:36:09 +04:00
}
2000-05-27 13:19:57 +04:00
/*******************************************************************
2002-09-25 19:19:00 +04:00
Dump a packet to a file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2012-03-05 16:28:07 +04:00
static void smb_dump ( const char * name , int type , const char * data )
2000-05-27 13:19:57 +04:00
{
2012-03-05 16:28:07 +04:00
size_t len ;
2000-05-27 13:19:57 +04:00
int fd , i ;
2007-11-12 08:46:52 +03:00
char * fname = NULL ;
if ( DEBUGLEVEL < 50 ) {
return ;
}
2000-05-27 13:19:57 +04:00
2012-03-05 16:28:07 +04:00
len = smb_len_tcp ( data ) + 4 ;
2000-05-27 13:19:57 +04:00
for ( i = 1 ; i < 100 ; i + + ) {
2012-03-22 01:34:34 +04:00
fname = talloc_asprintf ( talloc_tos ( ) ,
" /tmp/%s.%d.%s " ,
name ,
i ,
type ? " req " : " resp " ) ;
if ( fname = = NULL ) {
2007-11-12 08:46:52 +03:00
return ;
}
2000-05-27 13:19:57 +04:00
fd = open ( fname , O_WRONLY | O_CREAT | O_EXCL , 0644 ) ;
if ( fd ! = - 1 | | errno ! = EEXIST ) break ;
2012-03-22 01:34:34 +04:00
TALLOC_FREE ( fname ) ;
2000-05-27 13:19:57 +04:00
}
if ( fd ! = - 1 ) {
2002-01-20 00:29:20 +03:00
ssize_t ret = write ( fd , data , len ) ;
if ( ret ! = len )
DEBUG ( 0 , ( " smb_dump: problem: write returned %d \n " , ( int ) ret ) ) ;
2000-05-27 13:19:57 +04:00
close ( fd ) ;
2003-11-05 03:16:01 +03:00
DEBUG ( 0 , ( " created %s len %lu \n " , fname , ( unsigned long ) len ) ) ;
2000-05-27 13:19:57 +04:00
}
2012-03-22 01:34:34 +04:00
TALLOC_FREE ( fname ) ;
2000-05-27 13:19:57 +04:00
}
1998-08-17 17:11:34 +04:00
/****************************************************************************
2007-07-23 13:36:09 +04:00
Prepare everything for calling the actual request function , and potentially
call the request function via the " new " interface .
Return False if the " legacy " function needs to be called , everything is
prepared .
Return True if we ' re done .
I know this API sucks , but it is the one with the least code change I could
find .
1998-08-17 17:11:34 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
2012-03-05 16:28:07 +04:00
static connection_struct * switch_message ( uint8 type , struct smb_request * req )
1998-08-17 17:11:34 +04:00
{
2007-07-22 02:29:55 +04:00
int flags ;
2012-06-05 20:17:15 +04:00
uint64_t session_tag ;
2008-01-04 23:56:23 +03:00
connection_struct * conn = NULL ;
2010-06-12 15:23:10 +04:00
struct smbd_server_connection * sconn = req - > sconn ;
2012-04-25 21:36:20 +04:00
NTTIME now = timeval_to_nttime ( & req - > request_time ) ;
struct smbXsrv_session * session = NULL ;
NTSTATUS status ;
2001-01-24 22:34:53 +03:00
2002-09-25 19:19:00 +04:00
errno = 0 ;
2005-04-02 03:11:28 +04:00
2008-10-19 17:17:12 +04:00
if ( smb_messages [ type ] . fn = = NULL ) {
2002-09-25 19:19:00 +04:00
DEBUG ( 0 , ( " Unknown message type %d! \n " , type ) ) ;
2012-03-05 16:28:07 +04:00
smb_dump ( " Unknown " , 1 , ( const char * ) req - > inbuf ) ;
2007-07-23 13:36:09 +04:00
reply_unknown_new ( req , type ) ;
2008-01-04 23:56:23 +03:00
return NULL ;
2007-07-22 02:29:55 +04:00
}
2002-09-25 19:19:00 +04:00
2007-07-22 02:29:55 +04:00
flags = smb_messages [ type ] . flags ;
2002-09-25 19:19:00 +04:00
2007-07-22 02:29:55 +04:00
/* In share mode security we must ignore the vuid. */
2012-02-03 11:03:10 +04:00
session_tag = req - > vuid ;
2008-01-04 23:56:23 +03:00
conn = req - > conn ;
2001-01-24 22:04:56 +03:00
2007-07-22 15:38:11 +04:00
DEBUG ( 3 , ( " switch message %s (pid %d) conn 0x%lx \n " , smb_fn_name ( type ) ,
2012-03-24 23:17:08 +04:00
( int ) getpid ( ) , ( unsigned long ) conn ) ) ;
2007-07-22 02:29:55 +04:00
2012-03-05 16:28:07 +04:00
smb_dump ( smb_fn_name ( type ) , 1 , ( const char * ) req - > inbuf ) ;
2001-01-24 22:04:56 +03:00
2007-07-22 02:29:55 +04:00
/* Ensure this value is replaced in the incoming packet. */
2011-05-05 21:41:59 +04:00
SSVAL ( discard_const_p ( uint8_t , req - > inbuf ) , smb_uid , session_tag ) ;
2001-01-24 22:04:56 +03:00
2007-07-22 02:29:55 +04:00
/*
* Ensure the correct username is in current_user_info . This is a
* really ugly bugfix for problems with multiple session_setup_and_X ' s
* being done and allowing % U and % G substitutions to work correctly .
* There is a reason this code is done here , don ' t move it unless you
2007-07-22 15:38:11 +04:00
* know what you ' re doing . . . : - ) .
* JRA .
2007-07-22 02:29:55 +04:00
*/
2012-04-25 21:36:20 +04:00
/*
* lookup an existing session
*
* Note : for now we only check for NT_STATUS_NETWORK_SESSION_EXPIRED
* here , the main check is still in change_to_user ( )
*/
status = smb1srv_session_lookup ( sconn - > conn ,
session_tag ,
now ,
& session ) ;
if ( NT_STATUS_EQUAL ( status , NT_STATUS_NETWORK_SESSION_EXPIRED ) ) {
switch ( type ) {
case SMBsesssetupX :
status = NT_STATUS_OK ;
break ;
default :
DEBUG ( 1 , ( " Error: session %llu is expired, mid=%llu. \n " ,
( unsigned long long ) session_tag ,
( unsigned long long ) req - > mid ) ) ;
reply_nterror ( req , NT_STATUS_NETWORK_SESSION_EXPIRED ) ;
return conn ;
}
}
2009-05-26 17:21:16 +04:00
if ( session_tag ! = sconn - > smb1 . sessions . last_session_tag ) {
2012-06-05 14:04:15 +04:00
struct user_struct * vuser = NULL ;
2007-07-22 02:29:55 +04:00
2009-05-26 17:21:16 +04:00
sconn - > smb1 . sessions . last_session_tag = session_tag ;
2012-04-25 21:36:20 +04:00
if ( session ) {
vuser = session - > compat ;
}
if ( vuser ) {
set_current_user_info (
vuser - > session_info - > unix_info - > sanitized_username ,
vuser - > session_info - > unix_info - > unix_name ,
vuser - > session_info - > info - > domain_name ) ;
2005-06-14 00:42:21 +04:00
}
2007-07-22 02:29:55 +04:00
}
2009-07-14 22:25:45 +04:00
2007-07-22 02:29:55 +04:00
/* Does this call need to be run as the connected user? */
if ( flags & AS_USER ) {
2001-06-20 07:05:09 +04:00
2007-07-22 02:29:55 +04:00
/* Does this call need a valid tree connection? */
if ( ! conn ) {
2007-07-22 15:38:11 +04:00
/*
* Amazingly , the error code depends on the command
* ( from Samba4 ) .
*/
2007-07-22 02:29:55 +04:00
if ( type = = SMBntcreateX ) {
2007-07-23 13:36:09 +04:00
reply_nterror ( req , NT_STATUS_INVALID_HANDLE ) ;
2007-07-22 02:29:55 +04:00
} else {
2009-12-21 22:05:25 +03:00
reply_nterror ( req , NT_STATUS_NETWORK_NAME_DELETED ) ;
2006-06-20 06:38:28 +04:00
}
2008-01-04 23:56:23 +03:00
return NULL ;
2007-07-22 02:29:55 +04:00
}
2009-07-14 22:25:45 +04:00
2007-07-22 02:29:55 +04:00
if ( ! change_to_user ( conn , session_tag ) ) {
2009-04-23 03:30:55 +04:00
DEBUG ( 0 , ( " Error: Could not change to user. Removing "
2010-04-13 08:40:28 +04:00
" deferred open, mid=%llu. \n " ,
( unsigned long long ) req - > mid ) ) ;
2009-12-21 22:16:38 +03:00
reply_force_doserror ( req , ERRSRV , ERRbaduid ) ;
2008-01-04 23:56:23 +03:00
return conn ;
2007-07-22 02:29:55 +04:00
}
1998-08-17 17:11:34 +04:00
2007-07-22 02:29:55 +04:00
/* All NEED_WRITE and CAN_IPC flags must also have AS_USER. */
2001-01-24 22:04:56 +03:00
2007-07-22 02:29:55 +04:00
/* Does it need write permission? */
if ( ( flags & NEED_WRITE ) & & ! CAN_WRITE ( conn ) ) {
2007-07-23 13:36:09 +04:00
reply_nterror ( req , NT_STATUS_MEDIA_WRITE_PROTECTED ) ;
2008-01-04 23:56:23 +03:00
return conn ;
2006-06-20 06:38:28 +04:00
}
2001-01-24 22:04:56 +03:00
2007-07-22 02:29:55 +04:00
/* IPC services are limited */
if ( IS_IPC ( conn ) & & ! ( flags & CAN_IPC ) ) {
2009-12-21 22:05:25 +03:00
reply_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
2008-01-04 23:56:23 +03:00
return conn ;
2005-04-15 03:32:56 +04:00
}
2007-07-22 02:29:55 +04:00
} else {
/* This call needs to be run as root */
change_to_root_user ( ) ;
}
2001-01-24 22:04:56 +03:00
2007-07-22 02:29:55 +04:00
/* load service specific parameters */
if ( conn ) {
2008-01-04 23:56:23 +03:00
if ( req - > encrypted ) {
conn - > encrypted_tid = true ;
/* encrypted required from now on. */
2012-08-17 11:40:52 +04:00
conn - > encrypt_level = SMB_SIGNING_REQUIRED ;
2008-01-04 23:56:23 +03:00
} else if ( ENCRYPTION_REQUIRED ( conn ) ) {
2008-11-03 00:33:20 +03:00
if ( req - > cmd ! = SMBtrans2 & & req - > cmd ! = SMBtranss2 ) {
2012-08-17 11:42:27 +04:00
DEBUG ( 1 , ( " service[%s] requires encryption "
" %s ACCESS_DENIED. mid=%llu \n " ,
lp_servicename ( talloc_tos ( ) , SNUM ( conn ) ) ,
smb_fn_name ( type ) ,
( unsigned long long ) req - > mid ) ) ;
reply_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
2008-01-04 23:56:23 +03:00
return conn ;
}
}
2007-07-23 13:36:09 +04:00
if ( ! set_current_service ( conn , SVAL ( req - > inbuf , smb_flg ) ,
2007-07-22 15:38:11 +04:00
( flags & ( AS_USER | DO_CHDIR )
? True : False ) ) ) {
2009-12-21 22:05:25 +03:00
reply_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
2008-01-04 23:56:23 +03:00
return conn ;
2007-12-28 10:51:03 +03:00
}
2007-07-22 02:29:55 +04:00
conn - > num_smb_operations + + ;
}
2001-01-24 22:04:56 +03:00
2012-03-05 19:56:53 +04:00
/*
* Does this protocol need to be run as guest ? ( Only archane
* messenger service requests have this . . . )
*/
if ( flags & AS_GUEST ) {
char * raddr ;
bool ok ;
2011-06-16 17:39:25 +04:00
2012-03-05 19:56:53 +04:00
if ( ! change_to_guest ( ) ) {
reply_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return conn ;
}
raddr = tsocket_address_inet_addr_string ( sconn - > remote_address ,
talloc_tos ( ) ) ;
if ( raddr = = NULL ) {
reply_nterror ( req , NT_STATUS_NO_MEMORY ) ;
return conn ;
}
/*
* Haven ' t we checked this in smbd_process already ? ? ?
*/
ok = allow_access ( lp_hostsdeny ( - 1 ) , lp_hostsallow ( - 1 ) ,
sconn - > remote_hostname , raddr ) ;
TALLOC_FREE ( raddr ) ;
if ( ! ok ) {
reply_nterror ( req , NT_STATUS_ACCESS_DENIED ) ;
return conn ;
}
2007-07-23 13:36:09 +04:00
}
2008-10-19 17:17:12 +04:00
smb_messages [ type ] . fn ( req ) ;
2008-01-04 23:56:23 +03:00
return req - > conn ;
1998-09-05 09:07:05 +04:00
}
/****************************************************************************
2002-09-25 19:19:00 +04:00
Construct a reply to the incoming packet .
1998-09-05 09:07:05 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-09-25 19:19:00 +04:00
2010-10-03 20:16:21 +04:00
static void construct_reply ( struct smbd_server_connection * sconn ,
char * inbuf , int size , size_t unread_bytes ,
2009-03-09 11:47:59 +03:00
uint32_t seqnum , bool encrypted ,
2009-02-09 10:10:34 +03:00
struct smb_perfcount_data * deferred_pcd )
1998-09-05 09:07:05 +04:00
{
2008-01-04 23:56:23 +03:00
connection_struct * conn ;
2007-07-23 13:36:09 +04:00
struct smb_request * req ;
1998-09-05 09:07:05 +04:00
2007-08-30 23:48:31 +04:00
if ( ! ( req = talloc ( talloc_tos ( ) , struct smb_request ) ) ) {
2007-07-23 13:36:09 +04:00
smb_panic ( " could not allocate smb_request " ) ;
}
2009-02-09 10:10:34 +03:00
2010-10-03 20:16:21 +04:00
if ( ! init_smb_request ( req , sconn , ( uint8 * ) inbuf , unread_bytes ,
encrypted , seqnum ) ) {
2010-03-11 13:33:01 +03:00
exit_server_cleanly ( " Invalid SMB request " ) ;
}
2008-11-03 23:55:05 +03:00
req - > inbuf = ( uint8_t * ) talloc_move ( req , & inbuf ) ;
1998-09-05 09:07:05 +04:00
2009-02-09 10:10:34 +03:00
/* we popped this message off the queue - keep original perf data */
if ( deferred_pcd )
req - > pcd = * deferred_pcd ;
else {
SMB_PERFCOUNT_START ( & req - > pcd ) ;
SMB_PERFCOUNT_SET_OP ( & req - > pcd , req - > cmd ) ;
SMB_PERFCOUNT_SET_MSGLEN_IN ( & req - > pcd , size ) ;
}
2012-03-05 16:28:07 +04:00
conn = switch_message ( req - > cmd , req ) ;
1998-09-05 09:07:05 +04:00
2007-08-27 16:04:09 +04:00
if ( req - > outbuf = = NULL ) {
return ;
2007-07-23 13:36:09 +04:00
}
1998-09-05 09:07:05 +04:00
2007-08-27 16:04:09 +04:00
if ( CVAL ( req - > outbuf , 0 ) = = 0 ) {
show_msg ( ( char * ) req - > outbuf ) ;
}
1998-09-05 09:07:05 +04:00
2010-08-24 22:10:20 +04:00
if ( ! srv_send_smb ( req - > sconn ,
2008-01-04 23:56:23 +03:00
( char * ) req - > outbuf ,
2009-03-09 11:47:59 +03:00
true , req - > seqnum + 1 ,
2009-02-09 10:10:34 +03:00
IS_CONN_ENCRYPTED ( conn ) | | req - > encrypted ,
& req - > pcd ) ) {
2008-01-04 23:56:23 +03:00
exit_server_cleanly ( " construct_reply: srv_send_smb failed. " ) ;
2007-04-20 00:50:49 +04:00
}
2007-07-23 13:36:09 +04:00
TALLOC_FREE ( req ) ;
return ;
1998-09-05 09:07:05 +04:00
}
2012-02-28 03:56:10 +04:00
static void construct_reply_chain ( struct smbd_server_connection * sconn ,
char * inbuf , int size , uint32_t seqnum ,
bool encrypted ,
struct smb_perfcount_data * deferred_pcd )
{
struct smb_request * * reqs = NULL ;
2012-03-04 15:10:04 +04:00
struct smb_request * req ;
unsigned num_reqs ;
2012-02-28 03:56:10 +04:00
bool ok ;
ok = smb1_parse_chain ( talloc_tos ( ) , ( uint8_t * ) inbuf , sconn , encrypted ,
seqnum , & reqs , & num_reqs ) ;
if ( ! ok ) {
2012-03-04 15:10:04 +04:00
char errbuf [ smb_size ] ;
error_packet ( errbuf , 0 , 0 , NT_STATUS_INVALID_PARAMETER ,
__LINE__ , __FILE__ ) ;
if ( ! srv_send_smb ( sconn , errbuf , true , seqnum , encrypted ,
NULL ) ) {
exit_server_cleanly ( " construct_reply_chain: "
" srv_send_smb failed. " ) ;
}
return ;
2012-02-28 03:56:10 +04:00
}
2012-03-04 15:10:04 +04:00
req = reqs [ 0 ] ;
req - > inbuf = ( uint8_t * ) talloc_move ( reqs , & inbuf ) ;
2012-02-28 03:56:10 +04:00
2012-03-04 15:10:04 +04:00
req - > conn = switch_message ( req - > cmd , req ) ;
2012-02-28 03:56:10 +04:00
2012-03-04 15:10:04 +04:00
if ( req - > outbuf = = NULL ) {
/*
* Request has suspended itself , will come
* back here .
*/
return ;
}
smb_request_done ( req ) ;
}
2012-02-28 03:56:10 +04:00
2012-03-04 15:10:04 +04:00
/*
* To be called from an async SMB handler that is potentially chained
* when it is finished for shipping .
*/
void smb_request_done ( struct smb_request * req )
{
struct smb_request * * reqs = NULL ;
struct smb_request * first_req ;
size_t i , num_reqs , next_index ;
NTSTATUS status ;
if ( req - > chain = = NULL ) {
first_req = req ;
goto shipit ;
2012-02-28 03:56:10 +04:00
}
2012-03-04 15:10:04 +04:00
reqs = req - > chain ;
num_reqs = talloc_array_length ( reqs ) ;
2012-02-28 03:56:10 +04:00
2012-03-04 15:10:04 +04:00
for ( i = 0 ; i < num_reqs ; i + + ) {
if ( reqs [ i ] = = req ) {
break ;
}
}
if ( i = = num_reqs ) {
2012-02-28 03:56:10 +04:00
/*
2012-03-04 15:10:04 +04:00
* Invalid chain , should not happen
2012-02-28 03:56:10 +04:00
*/
2012-03-04 15:10:04 +04:00
status = NT_STATUS_INTERNAL_ERROR ;
goto error ;
}
next_index = i + 1 ;
while ( ( next_index < num_reqs ) & & ( IVAL ( req - > outbuf , smb_rcls ) = = 0 ) ) {
struct smb_request * next = reqs [ next_index ] ;
2012-03-28 18:14:09 +04:00
struct smbXsrv_tcon * tcon ;
NTTIME now = timeval_to_nttime ( & req - > request_time ) ;
2012-03-04 15:10:04 +04:00
next - > vuid = SVAL ( req - > outbuf , smb_uid ) ;
next - > tid = SVAL ( req - > outbuf , smb_tid ) ;
2012-03-28 18:14:09 +04:00
status = smb1srv_tcon_lookup ( req - > sconn - > conn , req - > tid ,
now , & tcon ) ;
if ( NT_STATUS_IS_OK ( status ) ) {
req - > conn = tcon - > compat ;
} else {
req - > conn = NULL ;
}
2012-03-04 15:10:04 +04:00
next - > chain_fsp = req - > chain_fsp ;
next - > inbuf = ( uint8_t * ) req - > inbuf ;
req = next ;
req - > conn = switch_message ( req - > cmd , req ) ;
if ( req - > outbuf = = NULL ) {
/*
* Request has suspended itself , will come
* back here .
*/
return ;
}
next_index + = 1 ;
2012-02-28 03:56:10 +04:00
}
2012-03-04 15:10:04 +04:00
first_req = reqs [ 0 ] ;
2012-02-28 03:56:10 +04:00
for ( i = 1 ; i < next_index ; i + + ) {
2012-03-04 15:10:04 +04:00
bool ok ;
2012-02-28 03:56:10 +04:00
2012-03-04 15:10:04 +04:00
ok = smb_splice_chain ( & first_req - > outbuf , reqs [ i ] - > outbuf ) ;
2012-02-28 03:56:10 +04:00
if ( ! ok ) {
status = NT_STATUS_INTERNAL_ERROR ;
goto error ;
}
}
2012-03-04 15:10:04 +04:00
SSVAL ( first_req - > outbuf , smb_uid , SVAL ( req - > outbuf , smb_uid ) ) ;
SSVAL ( first_req - > outbuf , smb_tid , SVAL ( req - > outbuf , smb_tid ) ) ;
2012-02-28 03:56:10 +04:00
/*
* This scary statement intends to set the
* FLAGS2_32_BIT_ERROR_CODES flg2 field in first_req - > outbuf
* to the value last_req - > outbuf carries
*/
SSVAL ( first_req - > outbuf , smb_flg2 ,
( SVAL ( first_req - > outbuf , smb_flg2 ) & ~ FLAGS2_32_BIT_ERROR_CODES )
2012-03-04 15:10:04 +04:00
| ( SVAL ( req - > outbuf , smb_flg2 ) & FLAGS2_32_BIT_ERROR_CODES ) ) ;
2012-02-28 03:56:10 +04:00
/*
* Transfer the error codes from the subrequest to the main one
*/
2012-03-04 15:10:04 +04:00
SSVAL ( first_req - > outbuf , smb_rcls , SVAL ( req - > outbuf , smb_rcls ) ) ;
SSVAL ( first_req - > outbuf , smb_err , SVAL ( req - > outbuf , smb_err ) ) ;
2012-02-28 03:56:10 +04:00
2012-03-04 15:10:04 +04:00
_smb_setlen_large (
first_req - > outbuf , talloc_get_size ( first_req - > outbuf ) - 4 ) ;
2012-02-28 03:56:10 +04:00
shipit :
if ( ! srv_send_smb ( first_req - > sconn ,
( char * ) first_req - > outbuf ,
true , first_req - > seqnum + 1 ,
2012-03-04 15:10:04 +04:00
IS_CONN_ENCRYPTED ( req - > conn ) | | first_req - > encrypted ,
2012-02-28 03:56:10 +04:00
& first_req - > pcd ) ) {
exit_server_cleanly ( " construct_reply_chain: srv_send_smb "
" failed. " ) ;
}
2012-03-04 15:10:04 +04:00
TALLOC_FREE ( req ) ; /* non-chained case */
TALLOC_FREE ( reqs ) ; /* chained case */
2012-02-28 03:56:10 +04:00
return ;
error :
{
char errbuf [ smb_size ] ;
error_packet ( errbuf , 0 , 0 , status , __LINE__ , __FILE__ ) ;
2012-03-04 15:10:04 +04:00
if ( ! srv_send_smb ( req - > sconn , errbuf , true ,
req - > seqnum + 1 , req - > encrypted ,
2012-02-28 03:56:10 +04:00
NULL ) ) {
exit_server_cleanly ( " construct_reply_chain: "
" srv_send_smb failed. " ) ;
}
}
2012-03-04 15:10:04 +04:00
TALLOC_FREE ( req ) ; /* non-chained case */
TALLOC_FREE ( reqs ) ; /* chained case */
2012-02-28 03:56:10 +04:00
}
1998-09-05 09:07:05 +04:00
/****************************************************************************
2006-03-19 14:11:37 +03:00
Process an smb from the client
1998-09-05 09:07:05 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-10-03 20:04:05 +04:00
static void process_smb ( struct smbd_server_connection * sconn ,
2009-01-08 17:38:47 +03:00
uint8_t * inbuf , size_t nread , size_t unread_bytes ,
2009-03-09 11:47:59 +03:00
uint32_t seqnum , bool encrypted ,
struct smb_perfcount_data * deferred_pcd )
1998-09-05 09:07:05 +04:00
{
2003-07-16 22:06:27 +04:00
int msg_type = CVAL ( inbuf , 0 ) ;
DO_PROFILE_INC ( smb_count ) ;
2007-07-23 13:36:09 +04:00
DEBUG ( 6 , ( " got message type 0x%x of len 0x%x \n " , msg_type ,
smb_len ( inbuf ) ) ) ;
2010-08-24 22:47:29 +04:00
DEBUG ( 3 , ( " Transaction %d of length %d (%u toread) \n " ,
2010-10-03 20:04:05 +04:00
sconn - > trans_num , ( int ) nread , ( unsigned int ) unread_bytes ) ) ;
2003-07-16 22:06:27 +04:00
2011-07-12 10:55:58 +04:00
if ( msg_type ! = NBSSmessage ) {
2007-07-23 13:36:09 +04:00
/*
* NetBIOS session request , keepalive , etc .
*/
2010-10-03 20:04:05 +04:00
reply_special ( sconn , ( char * ) inbuf , nread ) ;
2009-01-08 17:38:47 +03:00
goto done ;
2007-07-23 13:36:09 +04:00
}
2003-07-16 22:06:27 +04:00
2010-10-03 20:04:05 +04:00
if ( sconn - > using_smb2 ) {
2010-06-10 06:12:02 +04:00
/* At this point we're not really using smb2,
* we make the decision here . . */
2009-05-14 16:17:28 +04:00
if ( smbd_is_smb2_header ( inbuf , nread ) ) {
2010-10-03 20:05:17 +04:00
smbd_smb2_first_negprot ( sconn , inbuf , nread ) ;
2009-05-14 16:17:28 +04:00
return ;
2011-08-05 18:44:01 +04:00
} else if ( nread > = smb_size & & valid_smb_header ( sconn , inbuf )
2010-04-28 09:15:17 +04:00
& & CVAL ( inbuf , smb_com ) ! = 0x72 ) {
/* This is a non-negprot SMB1 packet.
Disable SMB2 from now on . */
2010-10-03 20:05:17 +04:00
sconn - > using_smb2 = false ;
2009-05-14 16:17:28 +04:00
}
}
2012-01-05 14:58:17 +04:00
/* Make sure this is an SMB packet. smb_size contains NetBIOS header
* so subtract 4 from it . */
if ( ( nread < ( smb_size - 4 ) ) | | ! valid_smb_header ( sconn , inbuf ) ) {
DEBUG ( 2 , ( " Non-SMB packet of length %d. Terminating server \n " ,
smb_len ( inbuf ) ) ) ;
/* special magic for immediate exit */
if ( ( nread = = 9 ) & &
( IVAL ( inbuf , 4 ) = = 0x74697865 ) & &
lp_parm_bool ( - 1 , " smbd " , " suicide mode " , false ) ) {
uint8_t exitcode = CVAL ( inbuf , 8 ) ;
DEBUG ( 1 , ( " Exiting immediately with code %d \n " ,
( int ) exitcode ) ) ;
exit ( exitcode ) ;
}
exit_server_cleanly ( " Non-SMB packet " ) ;
}
2009-01-08 17:38:47 +03:00
show_msg ( ( char * ) inbuf ) ;
2007-07-23 13:36:09 +04:00
2012-02-28 03:56:10 +04:00
if ( ( unread_bytes = = 0 ) & & smb1_is_chain ( inbuf ) ) {
construct_reply_chain ( sconn , ( char * ) inbuf , nread ,
seqnum , encrypted , deferred_pcd ) ;
} else {
construct_reply ( sconn , ( char * ) inbuf , nread , unread_bytes ,
seqnum , encrypted , deferred_pcd ) ;
}
2010-10-03 20:04:05 +04:00
sconn - > trans_num + + ;
2009-01-08 17:38:47 +03:00
done :
2011-07-08 01:59:41 +04:00
sconn - > num_requests + + ;
2009-01-08 17:38:47 +03:00
/* The timeout_processing function isn't run nearly
often enough to implement ' max log size ' without
overrunning the size of the file by many megabytes .
This is especially true if we are running at debug
level 10. Checking every 50 SMBs is a nice
tradeoff of performance vs log file size overrun . */
2011-07-08 01:59:41 +04:00
if ( ( sconn - > num_requests % 50 ) = = 0 & &
2009-01-08 17:38:47 +03:00
need_to_check_log_size ( ) ) {
change_to_root_user ( ) ;
check_log_size ( ) ;
}
1998-09-05 09:07:05 +04:00
}
/****************************************************************************
2003-07-16 22:06:27 +04:00
Return a string containing the function name of a SMB command .
1998-09-05 09:07:05 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-07-16 22:06:27 +04:00
2002-08-17 19:27:10 +04:00
const char * smb_fn_name ( int type )
1998-09-05 09:07:05 +04:00
{
2003-01-03 11:28:12 +03:00
const char * unknown_name = " SMBunknown " ;
1998-09-05 09:07:05 +04:00
2001-01-24 22:04:56 +03:00
if ( smb_messages [ type ] . name = = NULL )
1998-09-05 09:07:05 +04:00
return ( unknown_name ) ;
2001-01-24 22:04:56 +03:00
return ( smb_messages [ type ] . name ) ;
1998-08-17 17:11:34 +04:00
}
1998-08-20 23:28:37 +04:00
/****************************************************************************
2003-12-01 05:25:56 +03:00
Helper functions for contruct_reply .
1998-08-20 23:28:37 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-08-20 00:03:41 +04:00
void add_to_common_flags2 ( uint32 v )
{
common_flags2 | = v ;
}
2003-12-01 05:25:56 +03:00
2003-12-01 09:19:17 +03:00
void remove_from_common_flags2 ( uint32 v )
2003-12-01 05:25:56 +03:00
{
2003-12-01 09:19:17 +03:00
common_flags2 & = ~ v ;
2003-12-01 05:25:56 +03:00
}
2008-12-19 20:07:44 +03:00
static void construct_reply_common ( struct smb_request * req , const char * inbuf ,
char * outbuf )
1998-08-20 23:28:37 +04:00
{
2011-09-10 00:44:44 +04:00
uint16_t in_flags2 = SVAL ( inbuf , smb_flg2 ) ;
uint16_t out_flags2 = common_flags2 ;
out_flags2 | = in_flags2 & FLAGS2_UNICODE_STRINGS ;
out_flags2 | = in_flags2 & FLAGS2_SMB_SECURITY_SIGNATURES ;
out_flags2 | = in_flags2 & FLAGS2_SMB_SECURITY_SIGNATURES_REQUIRED ;
2008-01-04 23:56:23 +03:00
srv_set_message ( outbuf , 0 , 0 , false ) ;
2010-01-23 15:33:10 +03:00
2008-12-19 20:07:44 +03:00
SCVAL ( outbuf , smb_com , req - > cmd ) ;
2006-04-11 05:43:13 +04:00
SIVAL ( outbuf , smb_rcls , 0 ) ;
2001-10-17 12:54:19 +04:00
SCVAL ( outbuf , smb_flg , FLAG_REPLY | ( CVAL ( inbuf , smb_flg ) & FLAG_CASELESS_PATHNAMES ) ) ;
2011-09-10 00:44:44 +04:00
SSVAL ( outbuf , smb_flg2 , out_flags2 ) ;
2006-04-11 05:43:13 +04:00
memset ( outbuf + smb_pidhigh , ' \0 ' , ( smb_tid - smb_pidhigh ) ) ;
2011-09-10 00:44:44 +04:00
memcpy ( outbuf + smb_ss_field , inbuf + smb_ss_field , 8 ) ;
2001-10-17 12:54:19 +04:00
SSVAL ( outbuf , smb_tid , SVAL ( inbuf , smb_tid ) ) ;
SSVAL ( outbuf , smb_pid , SVAL ( inbuf , smb_pid ) ) ;
SSVAL ( outbuf , smb_uid , SVAL ( inbuf , smb_uid ) ) ;
SSVAL ( outbuf , smb_mid , SVAL ( inbuf , smb_mid ) ) ;
1998-08-20 23:28:37 +04:00
}
1998-08-17 17:11:34 +04:00
2008-11-03 22:16:09 +03:00
void construct_reply_common_req ( struct smb_request * req , char * outbuf )
{
2011-05-05 21:41:59 +04:00
construct_reply_common ( req , ( const char * ) req - > inbuf , outbuf ) ;
2008-11-03 22:16:09 +03:00
}
2009-12-22 15:53:13 +03:00
/**
* @ brief Find the smb_cmd offset of the last command pushed
* @ param [ in ] buf The buffer we ' re building up
* @ retval Where can we put our next andx cmd ?
*
* While chaining requests , the " next " request we ' re looking at needs to put
* its SMB_Command before the data the previous request already built up added
* to the chain . Find the offset to the place where we have to put our cmd .
*/
static bool find_andx_cmd_ofs ( uint8_t * buf , size_t * pofs )
{
uint8_t cmd ;
size_t ofs ;
cmd = CVAL ( buf , smb_com ) ;
2012-02-24 19:02:02 +04:00
if ( ! is_andx_req ( cmd ) ) {
return false ;
}
2009-12-22 15:53:13 +03:00
ofs = smb_vwv0 ;
while ( CVAL ( buf , ofs ) ! = 0xff ) {
if ( ! is_andx_req ( CVAL ( buf , ofs ) ) ) {
return false ;
}
/*
* ofs is from start of smb header , so add the 4 length
* bytes . The next cmd is right after the wct field .
*/
ofs = SVAL ( buf , ofs + 2 ) + 4 + 1 ;
2012-02-24 19:02:02 +04:00
if ( ofs + 4 > = talloc_get_size ( buf ) ) {
return false ;
}
2009-12-22 15:53:13 +03:00
}
* pofs = ofs ;
return true ;
}
/**
* @ brief Do the smb chaining at a buffer level
* @ param [ in ] poutbuf Pointer to the talloc ' ed buffer to be modified
2012-02-24 19:16:23 +04:00
* @ param [ in ] andx_buf Buffer to be appended
2009-12-22 15:53:13 +03:00
*/
2012-02-24 19:16:23 +04:00
static bool smb_splice_chain ( uint8_t * * poutbuf , const uint8_t * andx_buf )
2009-12-22 15:53:13 +03:00
{
2012-02-24 19:16:23 +04:00
uint8_t smb_command = CVAL ( andx_buf , smb_com ) ;
uint8_t wct = CVAL ( andx_buf , smb_wct ) ;
const uint16_t * vwv = ( const uint16_t * ) ( andx_buf + smb_vwv ) ;
uint32_t num_bytes = smb_buflen ( andx_buf ) ;
2012-02-28 06:14:37 +04:00
const uint8_t * bytes = ( const uint8_t * ) smb_buf_const ( andx_buf ) ;
2012-02-24 19:16:23 +04:00
2009-12-22 15:53:13 +03:00
uint8_t * outbuf ;
size_t old_size , new_size ;
size_t ofs ;
size_t chain_padding = 0 ;
2012-02-24 19:16:23 +04:00
size_t andx_cmd_ofs ;
2009-12-22 15:53:13 +03:00
old_size = talloc_get_size ( * poutbuf ) ;
2012-02-24 19:16:23 +04:00
if ( ( old_size % 4 ) ! = 0 ) {
2009-12-22 15:53:13 +03:00
/*
* Align the wct field of subsequent requests to a 4 - byte
* boundary
*/
chain_padding = 4 - ( old_size % 4 ) ;
}
/*
* After the old request comes the new wct field ( 1 byte ) , the vwv ' s
2012-02-24 19:16:23 +04:00
* and the num_bytes field .
2009-12-22 15:53:13 +03:00
*/
new_size = old_size + chain_padding + 1 + wct * sizeof ( uint16_t ) + 2 ;
2012-02-24 19:16:23 +04:00
new_size + = num_bytes ;
2009-12-22 15:53:13 +03:00
if ( ( smb_command ! = SMBwriteX ) & & ( new_size > 0xffff ) ) {
2012-02-24 18:45:37 +04:00
DEBUG ( 1 , ( " smb_splice_chain: %u bytes won't fit \n " ,
2009-12-22 15:53:13 +03:00
( unsigned ) new_size ) ) ;
return false ;
}
2011-06-07 05:10:15 +04:00
outbuf = talloc_realloc ( NULL , * poutbuf , uint8_t , new_size ) ;
2009-12-22 15:53:13 +03:00
if ( outbuf = = NULL ) {
DEBUG ( 0 , ( " talloc failed \n " ) ) ;
return false ;
}
* poutbuf = outbuf ;
2012-02-24 19:16:23 +04:00
if ( ! find_andx_cmd_ofs ( outbuf , & andx_cmd_ofs ) ) {
DEBUG ( 1 , ( " invalid command chain \n " ) ) ;
* poutbuf = talloc_realloc ( NULL , * poutbuf , uint8_t , old_size ) ;
return false ;
}
2009-12-22 15:53:13 +03:00
2012-02-24 19:16:23 +04:00
if ( chain_padding ! = 0 ) {
memset ( outbuf + old_size , 0 , chain_padding ) ;
old_size + = chain_padding ;
2009-12-22 15:53:13 +03:00
}
2012-02-24 19:16:23 +04:00
SCVAL ( outbuf , andx_cmd_ofs , smb_command ) ;
SSVAL ( outbuf , andx_cmd_ofs + 2 , old_size - 4 ) ;
2009-12-22 15:53:13 +03:00
ofs = old_size ;
/*
* Push the chained request :
*
* wct field
*/
SCVAL ( outbuf , ofs , wct ) ;
ofs + = 1 ;
/*
* vwv array
*/
memcpy ( outbuf + ofs , vwv , sizeof ( uint16_t ) * wct ) ;
2012-03-01 02:44:36 +04:00
/*
* HACK ALERT
*
* Read & X has an offset into its data buffer at
* vwv [ 6 ] . reply_read_andx has no idea anymore that it ' s
* running from within a chain , so we have to fix up the
* offset here .
*
* Although it looks disgusting at this place , I want to keep
* it here . The alternative would be to push knowledge about
* the andx chain down into read & x again .
*/
if ( smb_command = = SMBreadX ) {
uint8_t * bytes_addr ;
if ( wct < 7 ) {
/*
* Invalid read & x response
*/
return false ;
}
bytes_addr = outbuf + ofs /* vwv start */
+ sizeof ( uint16_t ) * wct /* vwv array */
+ sizeof ( uint16_t ) ; /* bcc */
SSVAL ( outbuf + ofs , 6 * sizeof ( uint16_t ) ,
bytes_addr - outbuf - 4 ) ;
}
2009-12-22 15:53:13 +03:00
ofs + = sizeof ( uint16_t ) * wct ;
/*
* bcc ( byte count )
*/
2012-02-24 19:16:23 +04:00
SSVAL ( outbuf , ofs , num_bytes ) ;
2009-12-22 15:53:13 +03:00
ofs + = sizeof ( uint16_t ) ;
/*
* The bytes field
*/
memcpy ( outbuf + ofs , bytes , num_bytes ) ;
return true ;
}
2012-02-28 03:19:48 +04:00
bool smb1_is_chain ( const uint8_t * buf )
{
uint8_t cmd , wct , andx_cmd ;
cmd = CVAL ( buf , smb_com ) ;
if ( ! is_andx_req ( cmd ) ) {
return false ;
}
wct = CVAL ( buf , smb_wct ) ;
if ( wct < 2 ) {
return false ;
}
andx_cmd = CVAL ( buf , smb_vwv ) ;
return ( andx_cmd ! = 0xFF ) ;
}
bool smb1_walk_chain ( const uint8_t * buf ,
bool ( * fn ) ( uint8_t cmd ,
uint8_t wct , const uint16_t * vwv ,
uint16_t num_bytes , const uint8_t * bytes ,
void * private_data ) ,
void * private_data )
{
size_t smblen = smb_len ( buf ) ;
const char * smb_buf = smb_base ( buf ) ;
uint8_t cmd , chain_cmd ;
uint8_t wct ;
const uint16_t * vwv ;
uint16_t num_bytes ;
const uint8_t * bytes ;
cmd = CVAL ( buf , smb_com ) ;
wct = CVAL ( buf , smb_wct ) ;
vwv = ( const uint16_t * ) ( buf + smb_vwv ) ;
num_bytes = smb_buflen ( buf ) ;
bytes = ( uint8_t * ) smb_buf_const ( buf ) ;
if ( ! fn ( cmd , wct , vwv , num_bytes , bytes , private_data ) ) {
return false ;
}
if ( ! is_andx_req ( cmd ) ) {
return true ;
}
if ( wct < 2 ) {
return false ;
}
chain_cmd = CVAL ( vwv , 0 ) ;
while ( chain_cmd ! = 0xff ) {
uint32_t chain_offset ; /* uint32_t to avoid overflow */
size_t length_needed ;
ptrdiff_t vwv_offset ;
chain_offset = SVAL ( vwv + 1 , 0 ) ;
/*
* Check if the client tries to fool us . The chain
* offset needs to point beyond the current request in
* the chain , it needs to strictly grow . Otherwise we
* might be tricked into an endless loop always
* processing the same request over and over again . We
* used to assume that vwv and the byte buffer array
* in a chain are always attached , but OS / 2 the
* Write & X / Read & X chain puts the Read & X vwv array
* right behind the Write & X vwv chain . The Write & X bcc
* array is put behind the Read & X vwv array . So now we
* check whether the chain offset points strictly
* behind the previous vwv array . req - > buf points
* right after the vwv array of the previous
* request . See
* https : //bugzilla.samba.org/show_bug.cgi?id=8360 for
* more information .
*/
vwv_offset = ( ( const char * ) vwv - smb_buf ) ;
if ( chain_offset < = vwv_offset ) {
return false ;
}
/*
* Next check : Make sure the chain offset does not
* point beyond the overall smb request length .
*/
length_needed = chain_offset + 1 ; /* wct */
if ( length_needed > smblen ) {
return false ;
}
/*
* Now comes the pointer magic . Goal here is to set up
* vwv and buf correctly again . The chain offset ( the
* former vwv [ 1 ] ) points at the new wct field .
*/
wct = CVAL ( smb_buf , chain_offset ) ;
if ( is_andx_req ( chain_cmd ) & & ( wct < 2 ) ) {
return false ;
}
/*
* Next consistency check : Make the new vwv array fits
* in the overall smb request .
*/
length_needed + = ( wct + 1 ) * sizeof ( uint16_t ) ; /* vwv+buflen */
if ( length_needed > smblen ) {
return false ;
}
vwv = ( const uint16_t * ) ( smb_buf + chain_offset + 1 ) ;
/*
* Now grab the new byte buffer . . . .
*/
num_bytes = SVAL ( vwv + wct , 0 ) ;
/*
* . . and check that it fits .
*/
length_needed + = num_bytes ;
if ( length_needed > smblen ) {
return false ;
}
bytes = ( const uint8_t * ) ( vwv + wct + 1 ) ;
if ( ! fn ( chain_cmd , wct , vwv , num_bytes , bytes , private_data ) ) {
return false ;
}
if ( ! is_andx_req ( chain_cmd ) ) {
return true ;
}
chain_cmd = CVAL ( vwv , 0 ) ;
}
return true ;
}
static bool smb1_chain_length_cb ( uint8_t cmd ,
uint8_t wct , const uint16_t * vwv ,
uint16_t num_bytes , const uint8_t * bytes ,
void * private_data )
{
unsigned * count = ( unsigned * ) private_data ;
* count + = 1 ;
return true ;
}
unsigned smb1_chain_length ( const uint8_t * buf )
{
unsigned count = 0 ;
if ( ! smb1_walk_chain ( buf , smb1_chain_length_cb , & count ) ) {
return 0 ;
}
return count ;
}
struct smb1_parse_chain_state {
TALLOC_CTX * mem_ctx ;
const uint8_t * buf ;
struct smbd_server_connection * sconn ;
bool encrypted ;
uint32_t seqnum ;
struct smb_request * * reqs ;
unsigned num_reqs ;
} ;
static bool smb1_parse_chain_cb ( uint8_t cmd ,
uint8_t wct , const uint16_t * vwv ,
uint16_t num_bytes , const uint8_t * bytes ,
void * private_data )
{
struct smb1_parse_chain_state * state =
( struct smb1_parse_chain_state * ) private_data ;
struct smb_request * * reqs ;
struct smb_request * req ;
bool ok ;
reqs = talloc_realloc ( state - > mem_ctx , state - > reqs ,
struct smb_request * , state - > num_reqs + 1 ) ;
if ( reqs = = NULL ) {
return false ;
}
state - > reqs = reqs ;
req = talloc ( reqs , struct smb_request ) ;
if ( req = = NULL ) {
return false ;
}
ok = init_smb_request ( req , state - > sconn , state - > buf , 0 ,
state - > encrypted , state - > seqnum ) ;
if ( ! ok ) {
return false ;
}
req - > cmd = cmd ;
req - > wct = wct ;
req - > vwv = vwv ;
req - > buflen = num_bytes ;
req - > buf = bytes ;
reqs [ state - > num_reqs ] = req ;
state - > num_reqs + = 1 ;
return true ;
}
bool smb1_parse_chain ( TALLOC_CTX * mem_ctx , const uint8_t * buf ,
struct smbd_server_connection * sconn ,
bool encrypted , uint32_t seqnum ,
struct smb_request * * * reqs , unsigned * num_reqs )
{
struct smb1_parse_chain_state state ;
2012-03-04 15:10:04 +04:00
unsigned i ;
2012-02-28 03:19:48 +04:00
state . mem_ctx = mem_ctx ;
state . buf = buf ;
state . sconn = sconn ;
state . encrypted = encrypted ;
state . seqnum = seqnum ;
state . reqs = NULL ;
state . num_reqs = 0 ;
if ( ! smb1_walk_chain ( buf , smb1_parse_chain_cb , & state ) ) {
TALLOC_FREE ( state . reqs ) ;
return false ;
}
2012-03-04 15:10:04 +04:00
for ( i = 0 ; i < state . num_reqs ; i + + ) {
state . reqs [ i ] - > chain = state . reqs ;
}
2012-02-28 03:19:48 +04:00
* reqs = state . reqs ;
* num_reqs = state . num_reqs ;
return true ;
}
1999-12-13 16:27:58 +03:00
/****************************************************************************
Check if services need reloading .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2010-08-28 18:57:51 +04:00
static void check_reload ( struct smbd_server_connection * sconn , time_t t )
1999-12-13 16:27:58 +03:00
{
2010-12-23 14:14:21 +03:00
if ( last_smb_conf_reload_time = = 0 ) {
2003-07-16 22:06:27 +04:00
last_smb_conf_reload_time = t ;
2005-06-28 02:44:57 +04:00
}
2009-01-22 01:24:18 +03:00
if ( t > = last_smb_conf_reload_time + SMBD_RELOAD_CHECK ) {
2011-12-14 16:25:20 +04:00
reload_services ( sconn , conn_snum_used , true ) ;
2003-07-16 22:06:27 +04:00
last_smb_conf_reload_time = t ;
}
1999-12-13 16:27:58 +03:00
}
1998-08-17 17:11:34 +04:00
2010-03-18 14:50:22 +03:00
static bool fd_is_readable ( int fd )
{
2011-02-07 19:02:44 +03:00
int ret , revents ;
2010-03-18 14:50:22 +03:00
2011-02-07 19:02:44 +03:00
ret = poll_one_fd ( fd , POLLIN | POLLHUP , 0 , & revents ) ;
return ( ( ret > 0 ) & & ( ( revents & ( POLLIN | POLLHUP | POLLERR ) ) ! = 0 ) ) ;
2010-03-18 14:50:22 +03:00
}
2011-05-17 19:23:26 +04:00
static void smbd_server_connection_write_handler (
struct smbd_server_connection * sconn )
2009-01-08 17:38:47 +03:00
{
/* TODO: make write nonblocking */
}
2010-03-18 14:50:22 +03:00
static void smbd_server_connection_read_handler (
2011-05-17 19:23:26 +04:00
struct smbd_server_connection * sconn , int fd )
2009-01-08 17:38:47 +03:00
{
uint8_t * inbuf = NULL ;
size_t inbuf_len = 0 ;
size_t unread_bytes = 0 ;
bool encrypted = false ;
TALLOC_CTX * mem_ctx = talloc_tos ( ) ;
NTSTATUS status ;
2009-03-09 11:47:59 +03:00
uint32_t seqnum ;
2009-01-08 17:38:47 +03:00
2011-11-10 12:39:23 +04:00
bool from_client ;
if ( lp_async_smb_echo_handler ( )
& & fd_is_readable ( sconn - > smb1 . echo_handler . trusted_fd ) ) {
/*
* This is the super - ugly hack to prefer the packets
* forwarded by the echo handler over the ones by the
* client directly
*/
fd = sconn - > smb1 . echo_handler . trusted_fd ;
}
from_client = ( sconn - > sock = = fd ) ;
2010-03-18 11:23:48 +03:00
2010-03-18 14:50:22 +03:00
if ( from_client ) {
2011-05-17 19:23:26 +04:00
smbd_lock_socket ( sconn ) ;
2010-03-18 14:50:22 +03:00
2011-11-10 12:39:23 +04:00
if ( ! fd_is_readable ( fd ) ) {
DEBUG ( 10 , ( " the echo listener was faster \n " ) ) ;
smbd_unlock_socket ( sconn ) ;
return ;
2010-03-18 14:50:22 +03:00
}
2011-11-10 12:39:23 +04:00
}
/* TODO: make this completely nonblocking */
status = receive_smb_talloc ( mem_ctx , sconn , fd ,
( char * * ) ( void * ) & inbuf ,
0 , /* timeout */
& unread_bytes ,
& encrypted ,
& inbuf_len , & seqnum ,
false /* trusted channel */ ) ;
2010-03-18 14:50:22 +03:00
2011-11-10 12:39:23 +04:00
if ( from_client ) {
2011-05-17 19:23:26 +04:00
smbd_unlock_socket ( sconn ) ;
2010-03-18 11:23:48 +03:00
}
2009-01-08 17:38:47 +03:00
if ( NT_STATUS_EQUAL ( status , NT_STATUS_RETRY ) ) {
goto process ;
}
if ( NT_STATUS_IS_ERR ( status ) ) {
exit_server_cleanly ( " failed to receive smb request " ) ;
}
if ( ! NT_STATUS_IS_OK ( status ) ) {
return ;
}
process :
2011-05-17 19:23:26 +04:00
process_smb ( sconn , inbuf , inbuf_len , unread_bytes ,
2009-03-09 11:47:59 +03:00
seqnum , encrypted , NULL ) ;
2009-01-08 17:38:47 +03:00
}
static void smbd_server_connection_handler ( struct event_context * ev ,
struct fd_event * fde ,
uint16_t flags ,
void * private_data )
{
struct smbd_server_connection * conn = talloc_get_type ( private_data ,
struct smbd_server_connection ) ;
if ( flags & EVENT_FD_WRITE ) {
smbd_server_connection_write_handler ( conn ) ;
2010-08-12 14:48:30 +04:00
return ;
}
if ( flags & EVENT_FD_READ ) {
2010-08-15 13:35:23 +04:00
smbd_server_connection_read_handler ( conn , conn - > sock ) ;
2010-08-12 14:48:30 +04:00
return ;
2009-01-08 17:38:47 +03:00
}
}
2010-03-18 14:50:22 +03:00
static void smbd_server_echo_handler ( struct event_context * ev ,
struct fd_event * fde ,
uint16_t flags ,
void * private_data )
{
struct smbd_server_connection * conn = talloc_get_type ( private_data ,
struct smbd_server_connection ) ;
if ( flags & EVENT_FD_WRITE ) {
smbd_server_connection_write_handler ( conn ) ;
2010-08-12 14:48:43 +04:00
return ;
}
if ( flags & EVENT_FD_READ ) {
2010-03-18 14:50:22 +03:00
smbd_server_connection_read_handler (
conn , conn - > smb1 . echo_handler . trusted_fd ) ;
2010-08-12 14:48:43 +04:00
return ;
2010-03-18 14:50:22 +03:00
}
}
2009-01-22 14:36:42 +03:00
2011-06-02 01:49:43 +04:00
# ifdef CLUSTER_SUPPORT
2012-07-30 01:23:09 +04:00
struct smbd_release_ip_state {
struct smbd_server_connection * sconn ;
char addr [ INET6_ADDRSTRLEN ] ;
} ;
2009-01-22 14:36:42 +03:00
/****************************************************************************
received when we should release a specific IP
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void release_ip ( const char * ip , void * priv )
{
2012-07-30 01:23:09 +04:00
struct smbd_release_ip_state * state =
talloc_get_type_abort ( priv ,
struct smbd_release_ip_state ) ;
const char * addr = state - > addr ;
2010-08-28 19:09:56 +04:00
const char * p = addr ;
2009-05-08 03:11:43 +04:00
if ( strncmp ( " ::ffff: " , addr , 7 ) = = 0 ) {
p = addr + 7 ;
}
2011-05-19 20:13:40 +04:00
DEBUG ( 10 , ( " Got release IP message for %s, "
" our address is %s \n " , ip , p ) ) ;
2009-05-08 17:13:21 +04:00
if ( ( strcmp ( p , ip ) = = 0 ) | | ( ( p ! = addr ) & & strcmp ( addr , ip ) = = 0 ) ) {
2009-01-22 14:36:42 +03:00
DEBUG ( 0 , ( " Got release IP message for our IP %s - exiting immediately \n " ,
ip ) ) ;
2012-07-30 01:23:09 +04:00
/*
* With SMB2 we should do a clean disconnect ,
* the previous_session_id in the session setup
* will cleanup the old session , tcons and opens .
*
* A clean disconnect is needed in order to support
* durable handles .
*
* Note : typically this is never triggered
* as we got a TCP RST ( triggered by ctdb event scripts )
* before we get CTDB_SRVID_RELEASE_IP .
*
* We used to call _exit ( 1 ) here , but as this was mostly never
* triggered and has implication on our process model ,
* we can just use smbd_server_connection_terminate ( )
* ( also for SMB1 ) .
*/
smbd_server_connection_terminate ( state - > sconn ,
" CTDB_SRVID_RELEASE_IP " ) ;
return ;
2009-01-22 14:36:42 +03:00
}
}
2012-07-30 01:25:12 +04:00
static NTSTATUS smbd_register_ips ( struct smbd_server_connection * sconn ,
struct sockaddr_storage * srv ,
struct sockaddr_storage * clnt )
{
2012-07-30 01:23:09 +04:00
struct smbd_release_ip_state * state ;
2012-07-30 01:25:12 +04:00
struct ctdbd_connection * cconn ;
cconn = messaging_ctdbd_connection ( ) ;
if ( cconn = = NULL ) {
return NT_STATUS_NO_MEMORY ;
}
2012-07-30 01:23:09 +04:00
state = talloc_zero ( sconn , struct smbd_release_ip_state ) ;
if ( state = = NULL ) {
2012-07-30 01:25:12 +04:00
return NT_STATUS_NO_MEMORY ;
}
2012-07-30 01:23:09 +04:00
state - > sconn = sconn ;
if ( print_sockaddr ( state - > addr , sizeof ( state - > addr ) , srv ) = = NULL ) {
2012-07-30 01:25:12 +04:00
return NT_STATUS_NO_MEMORY ;
}
2012-07-30 01:23:09 +04:00
return ctdbd_register_ips ( cconn , srv , clnt , release_ip , state ) ;
2012-07-30 01:25:12 +04:00
}
2010-09-27 04:15:18 +04:00
static int client_get_tcp_info ( int sock , struct sockaddr_storage * server ,
2009-01-22 14:36:42 +03:00
struct sockaddr_storage * client )
{
socklen_t length ;
length = sizeof ( * server ) ;
2010-09-27 04:15:18 +04:00
if ( getsockname ( sock , ( struct sockaddr * ) server , & length ) ! = 0 ) {
2009-01-22 14:36:42 +03:00
return - 1 ;
}
length = sizeof ( * client ) ;
2010-09-27 04:15:18 +04:00
if ( getpeername ( sock , ( struct sockaddr * ) client , & length ) ! = 0 ) {
2009-01-22 14:36:42 +03:00
return - 1 ;
}
return 0 ;
}
# endif
/*
* Send keepalive packets to our client
*/
static bool keepalive_fn ( const struct timeval * now , void * private_data )
{
2011-09-12 19:30:51 +04:00
struct smbd_server_connection * sconn = talloc_get_type_abort (
private_data , struct smbd_server_connection ) ;
2010-03-19 14:02:27 +03:00
bool ret ;
2010-06-10 06:12:02 +04:00
if ( sconn - > using_smb2 ) {
2010-06-10 04:08:41 +04:00
/* Don't do keepalives on an SMB2 connection. */
return false ;
}
2011-12-12 14:20:06 +04:00
smbd_lock_socket ( sconn ) ;
2010-08-15 13:36:27 +04:00
ret = send_keepalive ( sconn - > sock ) ;
2011-12-12 14:20:06 +04:00
smbd_unlock_socket ( sconn ) ;
2010-03-19 14:02:27 +03:00
if ( ! ret ) {
2010-08-15 18:02:37 +04:00
char addr [ INET6_ADDRSTRLEN ] ;
/*
* Try and give an error message saying what
* client failed .
*/
DEBUG ( 0 , ( " send_keepalive failed for client %s. "
" Error %s - exiting \n " ,
get_peer_addr ( sconn - > sock , addr , sizeof ( addr ) ) ,
strerror ( errno ) ) ) ;
2009-01-22 14:36:42 +03:00
return False ;
}
return True ;
}
/*
* Do the recurring check if we ' re idle
*/
static bool deadtime_fn ( const struct timeval * now , void * private_data )
{
2010-08-07 15:23:07 +04:00
struct smbd_server_connection * sconn =
( struct smbd_server_connection * ) private_data ;
2010-03-31 06:54:41 +04:00
2009-05-27 13:15:44 +04:00
if ( ( conn_num_open ( sconn ) = = 0 )
| | ( conn_idle_all ( sconn , now - > tv_sec ) ) ) {
2010-10-19 22:11:56 +04:00
DEBUG ( 2 , ( " Closing idle connection \n " ) ) ;
2010-09-01 01:16:50 +04:00
messaging_send ( sconn - > msg_ctx ,
messaging_server_id ( sconn - > msg_ctx ) ,
2009-01-22 14:36:42 +03:00
MSG_SHUTDOWN , & data_blob_null ) ;
return False ;
}
return True ;
}
/*
* Do the recurring log file and smb . conf reload checks .
*/
static bool housekeeping_fn ( const struct timeval * now , void * private_data )
{
2010-08-28 18:56:47 +04:00
struct smbd_server_connection * sconn = talloc_get_type_abort (
private_data , struct smbd_server_connection ) ;
2010-12-23 14:14:21 +03:00
DEBUG ( 5 , ( " housekeeping \n " ) ) ;
2009-01-22 14:36:42 +03:00
change_to_root_user ( ) ;
/* update printer queue caches if necessary */
2010-08-28 18:56:47 +04:00
update_monitored_printq_cache ( sconn - > msg_ctx ) ;
2009-01-22 14:36:42 +03:00
/* check if we need to reload services */
2010-12-23 14:14:21 +03:00
check_reload ( sconn , time_mono ( NULL ) ) ;
2009-01-22 14:36:42 +03:00
/*
* Force a log file check .
*/
force_check_log_size ( ) ;
check_log_size ( ) ;
return true ;
}
2011-07-26 17:07:22 +04:00
/*
* Read an smb packet in the echo handler child , giving the parent
* smbd one second to react once the socket becomes readable .
*/
struct smbd_echo_read_state {
struct tevent_context * ev ;
struct smbd_server_connection * sconn ;
char * buf ;
size_t buflen ;
uint32_t seqnum ;
} ;
static void smbd_echo_read_readable ( struct tevent_req * subreq ) ;
static void smbd_echo_read_waited ( struct tevent_req * subreq ) ;
static struct tevent_req * smbd_echo_read_send (
TALLOC_CTX * mem_ctx , struct tevent_context * ev ,
struct smbd_server_connection * sconn )
{
struct tevent_req * req , * subreq ;
struct smbd_echo_read_state * state ;
req = tevent_req_create ( mem_ctx , & state ,
struct smbd_echo_read_state ) ;
if ( req = = NULL ) {
return NULL ;
}
state - > ev = ev ;
state - > sconn = sconn ;
subreq = wait_for_read_send ( state , ev , sconn - > sock ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return tevent_req_post ( req , ev ) ;
}
tevent_req_set_callback ( subreq , smbd_echo_read_readable , req ) ;
return req ;
}
static void smbd_echo_read_readable ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct smbd_echo_read_state * state = tevent_req_data (
req , struct smbd_echo_read_state ) ;
bool ok ;
int err ;
ok = wait_for_read_recv ( subreq , & err ) ;
TALLOC_FREE ( subreq ) ;
if ( ! ok ) {
tevent_req_nterror ( req , map_nt_error_from_unix ( err ) ) ;
return ;
}
/*
* Give the parent smbd one second to step in
*/
subreq = tevent_wakeup_send (
state , state - > ev , timeval_current_ofs ( 1 , 0 ) ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , smbd_echo_read_waited , req ) ;
}
static void smbd_echo_read_waited ( struct tevent_req * subreq )
{
struct tevent_req * req = tevent_req_callback_data (
subreq , struct tevent_req ) ;
struct smbd_echo_read_state * state = tevent_req_data (
req , struct smbd_echo_read_state ) ;
struct smbd_server_connection * sconn = state - > sconn ;
bool ok ;
NTSTATUS status ;
size_t unread = 0 ;
bool encrypted ;
ok = tevent_wakeup_recv ( subreq ) ;
TALLOC_FREE ( subreq ) ;
if ( ! ok ) {
tevent_req_nterror ( req , NT_STATUS_INTERNAL_ERROR ) ;
return ;
}
ok = smbd_lock_socket_internal ( sconn ) ;
if ( ! ok ) {
tevent_req_nterror ( req , map_nt_error_from_unix ( errno ) ) ;
DEBUG ( 0 , ( " %s: failed to lock socket \n " , __location__ ) ) ;
return ;
}
if ( ! fd_is_readable ( sconn - > sock ) ) {
DEBUG ( 10 , ( " echo_handler[%d] the parent smbd was faster \n " ,
2012-03-24 23:17:08 +04:00
( int ) getpid ( ) ) ) ;
2011-07-26 17:07:22 +04:00
ok = smbd_unlock_socket_internal ( sconn ) ;
if ( ! ok ) {
tevent_req_nterror ( req , map_nt_error_from_unix ( errno ) ) ;
DEBUG ( 1 , ( " %s: failed to unlock socket \n " ,
__location__ ) ) ;
return ;
}
subreq = wait_for_read_send ( state , state - > ev , sconn - > sock ) ;
if ( tevent_req_nomem ( subreq , req ) ) {
return ;
}
tevent_req_set_callback ( subreq , smbd_echo_read_readable , req ) ;
return ;
}
status = receive_smb_talloc ( state , sconn , sconn - > sock , & state - > buf ,
0 /* timeout */ ,
& unread ,
& encrypted ,
& state - > buflen ,
& state - > seqnum ,
false /* trusted_channel*/ ) ;
if ( tevent_req_nterror ( req , status ) ) {
tevent_req_nterror ( req , status ) ;
DEBUG ( 1 , ( " echo_handler[%d]: receive_smb_raw_talloc failed: %s \n " ,
2012-03-24 23:17:08 +04:00
( int ) getpid ( ) , nt_errstr ( status ) ) ) ;
2011-07-26 17:07:22 +04:00
return ;
}
ok = smbd_unlock_socket_internal ( sconn ) ;
if ( ! ok ) {
tevent_req_nterror ( req , map_nt_error_from_unix ( errno ) ) ;
DEBUG ( 1 , ( " %s: failed to unlock socket \n " , __location__ ) ) ;
return ;
}
tevent_req_done ( req ) ;
}
static NTSTATUS smbd_echo_read_recv ( struct tevent_req * req , TALLOC_CTX * mem_ctx ,
char * * pbuf , size_t * pbuflen , uint32_t * pseqnum )
{
struct smbd_echo_read_state * state = tevent_req_data (
req , struct smbd_echo_read_state ) ;
NTSTATUS status ;
if ( tevent_req_is_nterror ( req , & status ) ) {
return status ;
}
* pbuf = talloc_move ( mem_ctx , & state - > buf ) ;
* pbuflen = state - > buflen ;
* pseqnum = state - > seqnum ;
return NT_STATUS_OK ;
}
2010-03-18 14:50:22 +03:00
struct smbd_echo_state {
struct tevent_context * ev ;
struct iovec * pending ;
struct smbd_server_connection * sconn ;
int parent_pipe ;
struct tevent_fd * parent_fde ;
struct tevent_req * write_req ;
} ;
static void smbd_echo_writer_done ( struct tevent_req * req ) ;
static void smbd_echo_activate_writer ( struct smbd_echo_state * state )
{
int num_pending ;
if ( state - > write_req ! = NULL ) {
return ;
}
num_pending = talloc_array_length ( state - > pending ) ;
if ( num_pending = = 0 ) {
return ;
}
state - > write_req = writev_send ( state , state - > ev , NULL ,
state - > parent_pipe , false ,
state - > pending , num_pending ) ;
if ( state - > write_req = = NULL ) {
DEBUG ( 1 , ( " writev_send failed \n " ) ) ;
exit ( 1 ) ;
}
talloc_steal ( state - > write_req , state - > pending ) ;
state - > pending = NULL ;
tevent_req_set_callback ( state - > write_req , smbd_echo_writer_done ,
state ) ;
}
static void smbd_echo_writer_done ( struct tevent_req * req )
{
struct smbd_echo_state * state = tevent_req_callback_data (
req , struct smbd_echo_state ) ;
ssize_t written ;
int err ;
written = writev_recv ( req , & err ) ;
TALLOC_FREE ( req ) ;
state - > write_req = NULL ;
if ( written = = - 1 ) {
DEBUG ( 1 , ( " writev to parent failed: %s \n " , strerror ( err ) ) ) ;
exit ( 1 ) ;
}
2012-03-24 23:17:08 +04:00
DEBUG ( 10 , ( " echo_handler[%d]: forwarded pdu to main \n " , ( int ) getpid ( ) ) ) ;
2010-03-18 14:50:22 +03:00
smbd_echo_activate_writer ( state ) ;
}
2011-12-12 14:20:06 +04:00
static bool smbd_echo_reply ( struct smbd_echo_state * state ,
uint8_t * inbuf , size_t inbuf_len ,
2010-03-18 14:50:22 +03:00
uint32_t seqnum )
{
struct smb_request req ;
uint16_t num_replies ;
char * outbuf ;
bool ok ;
2011-07-12 10:55:58 +04:00
if ( ( inbuf_len = = 4 ) & & ( CVAL ( inbuf , 0 ) = = NBSSkeepalive ) ) {
2010-10-06 20:24:13 +04:00
DEBUG ( 10 , ( " Got netbios keepalive \n " ) ) ;
/*
* Just swallow it
*/
return true ;
}
2010-03-18 14:50:22 +03:00
if ( inbuf_len < smb_size ) {
DEBUG ( 10 , ( " Got short packet: %d bytes \n " , ( int ) inbuf_len ) ) ;
return false ;
}
2011-12-12 14:20:06 +04:00
if ( ! valid_smb_header ( state - > sconn , inbuf ) ) {
2010-03-18 14:50:22 +03:00
DEBUG ( 10 , ( " Got invalid SMB header \n " ) ) ;
return false ;
}
2011-12-12 14:20:06 +04:00
if ( ! init_smb_request ( & req , state - > sconn , inbuf , 0 , false ,
2010-06-12 13:01:27 +04:00
seqnum ) ) {
2010-03-18 14:50:22 +03:00
return false ;
}
req . inbuf = inbuf ;
DEBUG ( 10 , ( " smbecho handler got cmd %d (%s) \n " , ( int ) req . cmd ,
smb_messages [ req . cmd ] . name
? smb_messages [ req . cmd ] . name : " unknown " ) ) ;
if ( req . cmd ! = SMBecho ) {
return false ;
}
if ( req . wct < 1 ) {
return false ;
}
num_replies = SVAL ( req . vwv + 0 , 0 ) ;
if ( num_replies ! = 1 ) {
/* Not a Windows "Hey, you're still there?" request */
return false ;
}
2011-05-05 21:41:59 +04:00
if ( ! create_outbuf ( talloc_tos ( ) , & req , ( const char * ) req . inbuf , & outbuf ,
2010-03-18 14:50:22 +03:00
1 , req . buflen ) ) {
DEBUG ( 10 , ( " create_outbuf failed \n " ) ) ;
return false ;
}
req . outbuf = ( uint8_t * ) outbuf ;
SSVAL ( req . outbuf , smb_vwv0 , num_replies ) ;
if ( req . buflen > 0 ) {
memcpy ( smb_buf ( req . outbuf ) , req . buf , req . buflen ) ;
}
2010-08-24 22:10:20 +04:00
ok = srv_send_smb ( req . sconn ,
2010-03-18 14:50:22 +03:00
( char * ) outbuf ,
true , seqnum + 1 ,
false , & req . pcd ) ;
TALLOC_FREE ( outbuf ) ;
if ( ! ok ) {
exit ( 1 ) ;
}
return true ;
}
static void smbd_echo_exit ( struct tevent_context * ev ,
struct tevent_fd * fde , uint16_t flags ,
void * private_data )
{
DEBUG ( 2 , ( " smbd_echo_exit: lost connection to parent \n " ) ) ;
exit ( 0 ) ;
}
2011-07-26 17:39:29 +04:00
static void smbd_echo_got_packet ( struct tevent_req * req ) ;
2010-03-18 14:50:22 +03:00
static void smbd_echo_loop ( struct smbd_server_connection * sconn ,
int parent_pipe )
{
struct smbd_echo_state * state ;
2011-07-26 17:39:29 +04:00
struct tevent_req * read_req ;
2010-03-18 14:50:22 +03:00
state = talloc_zero ( sconn , struct smbd_echo_state ) ;
if ( state = = NULL ) {
DEBUG ( 1 , ( " talloc failed \n " ) ) ;
return ;
}
state - > sconn = sconn ;
state - > parent_pipe = parent_pipe ;
state - > ev = s3_tevent_context_init ( state ) ;
if ( state - > ev = = NULL ) {
DEBUG ( 1 , ( " tevent_context_init failed \n " ) ) ;
TALLOC_FREE ( state ) ;
return ;
}
state - > parent_fde = tevent_add_fd ( state - > ev , state , parent_pipe ,
TEVENT_FD_READ , smbd_echo_exit ,
state ) ;
if ( state - > parent_fde = = NULL ) {
DEBUG ( 1 , ( " tevent_add_fd failed \n " ) ) ;
TALLOC_FREE ( state ) ;
return ;
}
2011-07-26 17:39:29 +04:00
read_req = smbd_echo_read_send ( state , state - > ev , sconn ) ;
if ( read_req = = NULL ) {
DEBUG ( 1 , ( " smbd_echo_read_send failed \n " ) ) ;
2010-03-18 14:50:22 +03:00
TALLOC_FREE ( state ) ;
return ;
}
2011-07-26 17:39:29 +04:00
tevent_req_set_callback ( read_req , smbd_echo_got_packet , state ) ;
2010-03-18 14:50:22 +03:00
while ( true ) {
if ( tevent_loop_once ( state - > ev ) = = - 1 ) {
DEBUG ( 1 , ( " tevent_loop_once failed: %s \n " ,
strerror ( errno ) ) ) ;
break ;
}
}
TALLOC_FREE ( state ) ;
}
2011-07-26 17:39:29 +04:00
static void smbd_echo_got_packet ( struct tevent_req * req )
{
struct smbd_echo_state * state = tevent_req_callback_data (
req , struct smbd_echo_state ) ;
NTSTATUS status ;
char * buf = NULL ;
size_t buflen = 0 ;
uint32_t seqnum = 0 ;
bool reply ;
status = smbd_echo_read_recv ( req , state , & buf , & buflen , & seqnum ) ;
TALLOC_FREE ( req ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " smbd_echo_read_recv returned %s \n " ,
nt_errstr ( status ) ) ) ;
exit ( 1 ) ;
}
2011-12-12 14:20:06 +04:00
reply = smbd_echo_reply ( state , ( uint8_t * ) buf , buflen , seqnum ) ;
2011-07-26 17:39:29 +04:00
if ( ! reply ) {
size_t num_pending ;
struct iovec * tmp ;
struct iovec * iov ;
num_pending = talloc_array_length ( state - > pending ) ;
tmp = talloc_realloc ( state , state - > pending , struct iovec ,
num_pending + 1 ) ;
if ( tmp = = NULL ) {
DEBUG ( 1 , ( " talloc_realloc failed \n " ) ) ;
exit ( 1 ) ;
}
state - > pending = tmp ;
if ( buflen > = smb_size ) {
/*
* place the seqnum in the packet so that the main process
* can reply with signing
*/
SIVAL ( buf , smb_ss_field , seqnum ) ;
SIVAL ( buf , smb_ss_field + 4 , NT_STATUS_V ( NT_STATUS_OK ) ) ;
}
iov = & state - > pending [ num_pending ] ;
iov - > iov_base = buf ;
iov - > iov_len = buflen ;
DEBUG ( 10 , ( " echo_handler[%d]: forward to main \n " ,
2012-03-24 23:17:08 +04:00
( int ) getpid ( ) ) ) ;
2011-07-26 17:39:29 +04:00
smbd_echo_activate_writer ( state ) ;
}
req = smbd_echo_read_send ( state , state - > ev , state - > sconn ) ;
if ( req = = NULL ) {
DEBUG ( 1 , ( " smbd_echo_read_send failed \n " ) ) ;
exit ( 1 ) ;
}
tevent_req_set_callback ( req , smbd_echo_got_packet , state ) ;
}
2010-03-18 14:50:22 +03:00
/*
* Handle SMBecho requests in a forked child process
*/
2011-05-20 15:07:17 +04:00
bool fork_echo_handler ( struct smbd_server_connection * sconn )
2010-03-18 14:50:22 +03:00
{
int listener_pipe [ 2 ] ;
int res ;
pid_t child ;
res = pipe ( listener_pipe ) ;
if ( res = = - 1 ) {
DEBUG ( 1 , ( " pipe() failed: %s \n " , strerror ( errno ) ) ) ;
return false ;
}
sconn - > smb1 . echo_handler . socket_lock_fd = create_unlink_tmp ( lp_lockdir ( ) ) ;
if ( sconn - > smb1 . echo_handler . socket_lock_fd = = - 1 ) {
DEBUG ( 1 , ( " Could not create lock fd: %s \n " , strerror ( errno ) ) ) ;
goto fail ;
}
2012-03-24 23:17:08 +04:00
child = fork ( ) ;
2010-03-18 14:50:22 +03:00
if ( child = = 0 ) {
NTSTATUS status ;
close ( listener_pipe [ 0 ] ) ;
2010-10-06 17:05:59 +04:00
set_blocking ( listener_pipe [ 1 ] , false ) ;
2010-03-18 14:50:22 +03:00
2010-08-07 15:23:07 +04:00
status = reinit_after_fork ( sconn - > msg_ctx ,
2011-12-12 16:54:10 +04:00
sconn - > ev_ctx ,
2011-12-12 17:55:54 +04:00
false ) ;
2010-03-18 14:50:22 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 1 , ( " reinit_after_fork failed: %s \n " ,
nt_errstr ( status ) ) ) ;
exit ( 1 ) ;
}
smbd_echo_loop ( sconn , listener_pipe [ 1 ] ) ;
exit ( 0 ) ;
}
close ( listener_pipe [ 1 ] ) ;
listener_pipe [ 1 ] = - 1 ;
sconn - > smb1 . echo_handler . trusted_fd = listener_pipe [ 0 ] ;
2012-03-24 23:17:08 +04:00
DEBUG ( 10 , ( " fork_echo_handler: main[%d] echo_child[%d] \n " , ( int ) getpid ( ) , child ) ) ;
2010-03-18 14:50:22 +03:00
/*
* Without smb signing this is the same as the normal smbd
* listener . This needs to change once signing comes in .
*/
2011-12-12 16:54:10 +04:00
sconn - > smb1 . echo_handler . trusted_fde = tevent_add_fd ( sconn - > ev_ctx ,
2010-03-18 14:50:22 +03:00
sconn ,
sconn - > smb1 . echo_handler . trusted_fd ,
2011-12-12 16:54:10 +04:00
TEVENT_FD_READ ,
2010-03-18 14:50:22 +03:00
smbd_server_echo_handler ,
sconn ) ;
if ( sconn - > smb1 . echo_handler . trusted_fde = = NULL ) {
DEBUG ( 1 , ( " event_add_fd failed \n " ) ) ;
goto fail ;
}
return true ;
fail :
if ( listener_pipe [ 0 ] ! = - 1 ) {
close ( listener_pipe [ 0 ] ) ;
}
if ( listener_pipe [ 1 ] ! = - 1 ) {
close ( listener_pipe [ 1 ] ) ;
}
sconn - > smb1 . echo_handler . trusted_fd = - 1 ;
if ( sconn - > smb1 . echo_handler . socket_lock_fd ! = - 1 ) {
close ( sconn - > smb1 . echo_handler . socket_lock_fd ) ;
}
sconn - > smb1 . echo_handler . trusted_fd = - 1 ;
sconn - > smb1 . echo_handler . socket_lock_fd = - 1 ;
return false ;
}
2011-12-14 13:23:30 +04:00
static bool uid_in_use ( const struct user_struct * user , uid_t uid )
{
while ( user ) {
if ( user - > session_info & &
( user - > session_info - > unix_token - > uid = = uid ) ) {
return true ;
}
user = user - > next ;
}
return false ;
}
static bool gid_in_use ( const struct user_struct * user , gid_t gid )
{
while ( user ) {
if ( user - > session_info ! = NULL ) {
int i ;
struct security_unix_token * utok ;
utok = user - > session_info - > unix_token ;
if ( utok - > gid = = gid ) {
return true ;
}
for ( i = 0 ; i < utok - > ngroups ; i + + ) {
if ( utok - > groups [ i ] = = gid ) {
return true ;
}
}
}
user = user - > next ;
}
return false ;
}
static bool sid_in_use ( const struct user_struct * user ,
const struct dom_sid * psid )
{
while ( user ) {
struct security_token * tok ;
if ( user - > session_info = = NULL ) {
continue ;
}
tok = user - > session_info - > security_token ;
if ( tok = = NULL ) {
/*
* Not sure session_info - > security_token can
* ever be NULL . This check might be not
* necessary .
*/
continue ;
}
if ( security_token_has_sid ( tok , psid ) ) {
return true ;
}
user = user - > next ;
}
return false ;
}
static bool id_in_use ( const struct user_struct * user ,
const struct id_cache_ref * id )
{
switch ( id - > type ) {
case UID :
return uid_in_use ( user , id - > id . uid ) ;
case GID :
return gid_in_use ( user , id - > id . gid ) ;
case SID :
return sid_in_use ( user , & id - > id . sid ) ;
default :
break ;
}
return false ;
}
static void smbd_id_cache_kill ( struct messaging_context * msg_ctx ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
{
const char * msg = ( data & & data - > data )
? ( const char * ) data - > data : " <NULL> " ;
struct id_cache_ref id ;
struct smbd_server_connection * sconn =
talloc_get_type_abort ( private_data ,
struct smbd_server_connection ) ;
if ( ! id_cache_ref_parse ( msg , & id ) ) {
DEBUG ( 0 , ( " Invalid ?ID: %s \n " , msg ) ) ;
return ;
}
2012-03-03 08:41:43 +04:00
if ( id_in_use ( sconn - > users , & id ) ) {
2011-12-14 13:23:30 +04:00
exit_server_cleanly ( msg ) ;
}
id_cache_delete_from_cache ( & id ) ;
}
2011-12-15 17:45:56 +04:00
NTSTATUS smbXsrv_connection_init_tables ( struct smbXsrv_connection * conn ,
enum protocol_types protocol )
{
2012-03-16 18:01:27 +04:00
NTSTATUS status ;
2011-12-15 17:45:56 +04:00
set_Protocol ( protocol ) ;
conn - > protocol = protocol ;
2012-03-16 18:01:27 +04:00
if ( protocol > = PROTOCOL_SMB2_02 ) {
status = smb2srv_session_table_init ( conn ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2012-06-08 19:51:47 +04:00
status = smb2srv_open_table_init ( conn ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2012-03-28 18:14:09 +04:00
} else {
2012-04-01 23:19:53 +04:00
status = smb1srv_session_table_init ( conn ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2012-03-28 18:14:09 +04:00
status = smb1srv_tcon_table_init ( conn ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2012-06-08 19:51:47 +04:00
status = smb1srv_open_table_init ( conn ) ;
if ( ! NT_STATUS_IS_OK ( status ) ) {
return status ;
}
2012-03-16 18:01:27 +04:00
}
2011-12-15 17:45:56 +04:00
return NT_STATUS_OK ;
}
2012-06-08 16:07:51 +04:00
static void smbd_tevent_trace_callback ( enum tevent_trace_point point ,
void * private_data )
{
2012-06-20 10:53:10 +04:00
struct smbXsrv_connection * conn =
talloc_get_type_abort ( private_data ,
struct smbXsrv_connection ) ;
2012-06-08 16:07:51 +04:00
switch ( point ) {
case TEVENT_TRACE_BEFORE_WAIT :
2012-06-22 14:10:00 +04:00
/*
* This just removes compiler warning
* without profile support
*/
conn - > smbd_idle_profstamp = 0 ;
2012-06-20 10:53:10 +04:00
START_PROFILE_STAMP ( smbd_idle , conn - > smbd_idle_profstamp ) ;
2012-06-08 16:07:51 +04:00
break ;
case TEVENT_TRACE_AFTER_WAIT :
2012-06-20 10:53:10 +04:00
END_PROFILE_STAMP ( smbd_idle , conn - > smbd_idle_profstamp ) ;
2012-06-08 16:07:51 +04:00
break ;
}
}
2005-06-28 02:53:56 +04:00
/****************************************************************************
Process commands from the client
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2011-08-08 20:39:56 +04:00
void smbd_process ( struct tevent_context * ev_ctx ,
2012-05-24 15:46:11 +04:00
struct messaging_context * msg_ctx ,
int sock_fd ,
bool interactive )
2005-06-28 02:53:56 +04:00
{
2009-01-22 14:36:42 +03:00
TALLOC_CTX * frame = talloc_stackframe ( ) ;
2012-05-24 15:46:11 +04:00
struct smbXsrv_connection * conn ;
struct smbd_server_connection * sconn ;
2010-04-27 15:36:21 +04:00
struct sockaddr_storage ss ;
struct sockaddr * sa = NULL ;
2010-08-28 10:27:08 +04:00
socklen_t sa_socklen ;
2010-04-27 15:36:21 +04:00
struct tsocket_address * local_address = NULL ;
struct tsocket_address * remote_address = NULL ;
2011-12-12 11:46:26 +04:00
const char * locaddr = NULL ;
2010-04-27 15:36:21 +04:00
const char * remaddr = NULL ;
2011-06-16 17:39:25 +04:00
char * rhost ;
2010-04-27 15:36:21 +04:00
int ret ;
2009-01-22 14:36:42 +03:00
2012-05-24 15:46:11 +04:00
conn = talloc_zero ( ev_ctx , struct smbXsrv_connection ) ;
if ( conn = = NULL ) {
2011-12-15 17:45:56 +04:00
DEBUG ( 0 , ( " talloc_zero(struct smbXsrv_connection) \n " ) ) ;
exit_server_cleanly ( " talloc_zero(struct smbXsrv_connection). \n " ) ;
}
2012-05-24 15:46:11 +04:00
conn - > ev_ctx = ev_ctx ;
conn - > msg_ctx = msg_ctx ;
sconn = talloc_zero ( conn , struct smbd_server_connection ) ;
if ( ! sconn ) {
exit_server ( " failed to create smbd_server_connection " ) ;
}
conn - > sconn = sconn ;
sconn - > conn = conn ;
/*
* TODO : remove this . . . : - )
*/
global_smbXsrv_connection = conn ;
sconn - > ev_ctx = ev_ctx ;
sconn - > msg_ctx = msg_ctx ;
sconn - > sock = sock_fd ;
sconn - > smb1 . echo_handler . trusted_fd = - 1 ;
sconn - > smb1 . echo_handler . socket_lock_fd = - 1 ;
if ( ! interactive ) {
smbd_setup_sig_term_handler ( sconn ) ;
smbd_setup_sig_hup_handler ( sconn ) ;
if ( ! serverid_register ( messaging_server_id ( msg_ctx ) ,
FLAG_MSG_GENERAL | FLAG_MSG_SMBD
| FLAG_MSG_DBWRAP
| FLAG_MSG_PRINT_GENERAL ) ) {
exit_server_cleanly ( " Could not register myself in "
" serverid.tdb " ) ;
}
}
2012-02-27 07:24:30 +04:00
if ( lp_srv_maxprotocol ( ) > = PROTOCOL_SMB2_02 ) {
2010-06-10 06:12:02 +04:00
/*
2011-04-14 13:06:00 +04:00
* We ' re not making the decision here ,
2010-06-10 06:12:02 +04:00
* we ' re just allowing the client
* to decide between SMB1 and SMB2
* with the first negprot
* packet .
*/
2010-08-08 20:47:02 +04:00
sconn - > using_smb2 = true ;
2009-05-14 16:17:28 +04:00
}
2009-01-22 14:36:42 +03:00
/* Ensure child is set to blocking mode */
2010-08-15 13:43:46 +04:00
set_blocking ( sconn - > sock , True ) ;
2009-01-22 14:36:42 +03:00
2010-08-15 13:43:46 +04:00
set_socket_options ( sconn - > sock , " SO_KEEPALIVE " ) ;
set_socket_options ( sconn - > sock , lp_socket_options ( ) ) ;
2009-01-22 14:36:42 +03:00
2010-04-27 15:36:21 +04:00
sa = ( struct sockaddr * ) ( void * ) & ss ;
2010-08-28 10:27:08 +04:00
sa_socklen = sizeof ( ss ) ;
ret = getpeername ( sconn - > sock , sa , & sa_socklen ) ;
2010-04-27 15:36:21 +04:00
if ( ret ! = 0 ) {
int level = ( errno = = ENOTCONN ) ? 2 : 0 ;
DEBUG ( level , ( " getpeername() failed - %s \n " , strerror ( errno ) ) ) ;
2010-06-28 21:39:28 +04:00
exit_server_cleanly ( " getpeername() failed. \n " ) ;
2010-04-27 15:36:21 +04:00
}
2010-08-08 20:47:02 +04:00
ret = tsocket_address_bsd_from_sockaddr ( sconn ,
2010-08-28 10:27:08 +04:00
sa , sa_socklen ,
2010-04-27 15:36:21 +04:00
& remote_address ) ;
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " %s: tsocket_address_bsd_from_sockaddr remote failed - %s \n " ,
__location__ , strerror ( errno ) ) ) ;
2010-06-28 21:39:28 +04:00
exit_server_cleanly ( " tsocket_address_bsd_from_sockaddr remote failed. \n " ) ;
2010-04-27 15:36:21 +04:00
}
sa = ( struct sockaddr * ) ( void * ) & ss ;
2010-08-28 10:27:08 +04:00
sa_socklen = sizeof ( ss ) ;
ret = getsockname ( sconn - > sock , sa , & sa_socklen ) ;
2010-04-27 15:36:21 +04:00
if ( ret ! = 0 ) {
int level = ( errno = = ENOTCONN ) ? 2 : 0 ;
DEBUG ( level , ( " getsockname() failed - %s \n " , strerror ( errno ) ) ) ;
2010-06-28 21:39:28 +04:00
exit_server_cleanly ( " getsockname() failed. \n " ) ;
2010-04-27 15:36:21 +04:00
}
2010-08-08 20:47:02 +04:00
ret = tsocket_address_bsd_from_sockaddr ( sconn ,
2010-08-28 10:27:08 +04:00
sa , sa_socklen ,
2010-04-27 15:36:21 +04:00
& local_address ) ;
if ( ret ! = 0 ) {
DEBUG ( 0 , ( " %s: tsocket_address_bsd_from_sockaddr remote failed - %s \n " ,
__location__ , strerror ( errno ) ) ) ;
2010-06-28 21:39:28 +04:00
exit_server_cleanly ( " tsocket_address_bsd_from_sockaddr remote failed. \n " ) ;
2010-04-27 15:36:21 +04:00
}
2010-08-08 20:47:02 +04:00
sconn - > local_address = local_address ;
sconn - > remote_address = remote_address ;
2010-04-27 15:36:21 +04:00
2011-12-12 11:46:26 +04:00
if ( tsocket_address_is_inet ( local_address , " ip " ) ) {
locaddr = tsocket_address_inet_addr_string (
sconn - > local_address ,
talloc_tos ( ) ) ;
if ( locaddr = = NULL ) {
DEBUG ( 0 , ( " %s: tsocket_address_inet_addr_string local failed - %s \n " ,
__location__ , strerror ( errno ) ) ) ;
exit_server_cleanly ( " tsocket_address_inet_addr_string local failed. \n " ) ;
}
} else {
locaddr = " 0.0.0.0 " ;
}
2010-04-27 15:36:21 +04:00
if ( tsocket_address_is_inet ( remote_address , " ip " ) ) {
remaddr = tsocket_address_inet_addr_string (
2010-08-08 20:47:02 +04:00
sconn - > remote_address ,
2010-04-27 15:36:21 +04:00
talloc_tos ( ) ) ;
if ( remaddr = = NULL ) {
2011-06-16 17:32:00 +04:00
DEBUG ( 0 , ( " %s: tsocket_address_inet_addr_string remote failed - %s \n " ,
__location__ , strerror ( errno ) ) ) ;
exit_server_cleanly ( " tsocket_address_inet_addr_string remote failed. \n " ) ;
2010-04-27 15:36:21 +04:00
}
} else {
remaddr = " 0.0.0.0 " ;
}
2009-01-22 14:36:42 +03:00
/* this is needed so that we get decent entries
in smbstatus for port 445 connects */
2010-04-27 15:36:21 +04:00
set_remote_machine_name ( remaddr , false ) ;
2011-12-14 16:25:20 +04:00
reload_services ( sconn , conn_snum_used , true ) ;
2009-01-22 14:36:42 +03:00
2008-10-19 15:44:11 +04:00
/*
* Before the first packet , check the global hosts allow / hosts deny
* parameters before doing any parsing of packets passed to us by the
* client . This prevents attacks on our parsing code from hosts not in
* the hosts allow list .
*/
2011-06-16 17:39:25 +04:00
ret = get_remote_hostname ( remote_address ,
& rhost ,
talloc_tos ( ) ) ;
if ( ret < 0 ) {
DEBUG ( 0 , ( " %s: get_remote_hostname failed - %s \n " ,
__location__ , strerror ( errno ) ) ) ;
exit_server_cleanly ( " get_remote_hostname failed. \n " ) ;
}
if ( strequal ( rhost , " UNKNOWN " ) ) {
rhost = talloc_strdup ( talloc_tos ( ) , remaddr ) ;
}
sconn - > remote_hostname = talloc_move ( sconn , & rhost ) ;
2011-12-12 11:46:26 +04:00
sub_set_socket_ids ( remaddr ,
sconn - > remote_hostname ,
locaddr ) ;
2010-08-18 18:48:20 +04:00
if ( ! allow_access ( lp_hostsdeny ( - 1 ) , lp_hostsallow ( - 1 ) ,
2011-06-16 17:39:25 +04:00
sconn - > remote_hostname ,
remaddr ) ) {
2008-10-19 15:44:11 +04:00
/*
* send a negative session response " not listening on calling
* name "
*/
unsigned char buf [ 5 ] = { 0x83 , 0 , 0 , 1 , 0x81 } ;
2010-04-27 15:36:21 +04:00
DEBUG ( 1 , ( " Connection denied from %s to %s \n " ,
tsocket_address_string ( remote_address , talloc_tos ( ) ) ,
tsocket_address_string ( local_address , talloc_tos ( ) ) ) ) ;
2010-08-24 22:10:20 +04:00
( void ) srv_send_smb ( sconn , ( char * ) buf , false ,
2009-03-09 11:47:59 +03:00
0 , false , NULL ) ;
2008-10-19 15:44:11 +04:00
exit_server_cleanly ( " connection denied " ) ;
}
2010-04-27 15:36:21 +04:00
DEBUG ( 10 , ( " Connection allowed from %s to %s \n " ,
tsocket_address_string ( remote_address , talloc_tos ( ) ) ,
tsocket_address_string ( local_address , talloc_tos ( ) ) ) ) ;
2012-04-03 07:23:18 +04:00
if ( lp_preload_modules ( ) ) {
smb_load_modules ( lp_preload_modules ( ) ) ;
}
2009-01-22 14:36:42 +03:00
2009-02-09 10:10:34 +03:00
smb_perfcount_init ( ) ;
2009-01-22 14:36:42 +03:00
if ( ! init_account_policy ( ) ) {
exit_server ( " Could not open account policy tdb. \n " ) ;
}
2012-07-18 09:37:23 +04:00
if ( * lp_rootdir ( talloc_tos ( ) ) ) {
if ( chroot ( lp_rootdir ( talloc_tos ( ) ) ) ! = 0 ) {
DEBUG ( 0 , ( " Failed to change root to %s \n " ,
lp_rootdir ( talloc_tos ( ) ) ) ) ;
2009-02-14 02:02:32 +03:00
exit_server ( " Failed to chroot() " ) ;
}
if ( chdir ( " / " ) = = - 1 ) {
2012-07-18 09:37:23 +04:00
DEBUG ( 0 , ( " Failed to chdir to / on chroot to %s \n " , lp_rootdir ( talloc_tos ( ) ) ) ) ;
2009-01-22 14:36:42 +03:00
exit_server ( " Failed to chroot() " ) ;
}
2012-07-18 09:37:23 +04:00
DEBUG ( 0 , ( " Changed root to %s \n " , lp_rootdir ( talloc_tos ( ) ) ) ) ;
2009-01-22 14:36:42 +03:00
}
2010-08-08 20:47:02 +04:00
if ( ! srv_init_signing ( sconn ) ) {
2009-03-09 11:47:59 +03:00
exit_server ( " Failed to init smb_signing " ) ;
}
2012-05-24 14:26:46 +04:00
if ( ! file_init ( sconn ) ) {
exit_server ( " file_init() failed " ) ;
}
2009-01-22 14:36:42 +03:00
/* Setup oplocks */
2011-12-13 16:13:53 +04:00
if ( ! init_oplocks ( sconn ) )
2009-01-22 14:36:42 +03:00
exit_server ( " Failed to init oplocks " ) ;
/* register our message handlers */
2011-12-13 11:11:58 +04:00
messaging_register ( sconn - > msg_ctx , sconn ,
2009-01-22 14:36:42 +03:00
MSG_SMB_FORCE_TDIS , msg_force_tdis ) ;
2011-12-12 18:45:07 +04:00
messaging_register ( sconn - > msg_ctx , sconn ,
2009-01-22 14:36:42 +03:00
MSG_SMB_CLOSE_FILE , msg_close_file ) ;
2011-12-13 11:11:58 +04:00
messaging_register ( sconn - > msg_ctx , sconn ,
2011-12-13 11:19:06 +04:00
MSG_SMB_FILE_RENAME , msg_file_was_renamed ) ;
2009-01-22 14:36:42 +03:00
2011-12-14 13:23:30 +04:00
id_cache_register_msgs ( sconn - > msg_ctx ) ;
messaging_deregister ( sconn - > msg_ctx , ID_CACHE_KILL , NULL ) ;
messaging_register ( sconn - > msg_ctx , sconn ,
ID_CACHE_KILL , smbd_id_cache_kill ) ;
2011-12-14 15:39:36 +04:00
messaging_deregister ( sconn - > msg_ctx ,
MSG_SMB_CONF_UPDATED , sconn - > ev_ctx ) ;
messaging_register ( sconn - > msg_ctx , sconn ,
MSG_SMB_CONF_UPDATED , smbd_conf_updated ) ;
2009-06-17 02:11:32 +04:00
/*
* Use the default MSG_DEBUG handler to avoid rebroadcasting
* MSGs to all child processes
*/
2010-08-08 20:48:01 +04:00
messaging_deregister ( sconn - > msg_ctx ,
2009-06-17 02:11:32 +04:00
MSG_DEBUG , NULL ) ;
2010-08-08 20:48:01 +04:00
messaging_register ( sconn - > msg_ctx , NULL ,
2009-06-17 02:11:32 +04:00
MSG_DEBUG , debug_message ) ;
2009-01-22 14:36:42 +03:00
if ( ( lp_keepalive ( ) ! = 0 )
2011-08-08 20:39:56 +04:00
& & ! ( event_add_idle ( ev_ctx , NULL ,
2009-01-22 14:36:42 +03:00
timeval_set ( lp_keepalive ( ) , 0 ) ,
" keepalive " , keepalive_fn ,
2011-09-12 19:30:51 +04:00
sconn ) ) ) {
2009-01-22 14:36:42 +03:00
DEBUG ( 0 , ( " Could not add keepalive event \n " ) ) ;
exit ( 1 ) ;
}
2011-08-08 20:39:56 +04:00
if ( ! ( event_add_idle ( ev_ctx , NULL ,
2009-01-22 14:36:42 +03:00
timeval_set ( IDLE_CLOSED_TIMEOUT , 0 ) ,
2010-08-08 20:47:02 +04:00
" deadtime " , deadtime_fn , sconn ) ) ) {
2009-01-22 14:36:42 +03:00
DEBUG ( 0 , ( " Could not add deadtime event \n " ) ) ;
exit ( 1 ) ;
2009-01-08 17:38:47 +03:00
}
2009-01-22 14:36:42 +03:00
2011-08-08 20:39:56 +04:00
if ( ! ( event_add_idle ( ev_ctx , NULL ,
2010-12-23 14:14:21 +03:00
timeval_set ( SMBD_HOUSEKEEPING_INTERVAL , 0 ) ,
2010-08-28 18:56:47 +04:00
" housekeeping " , housekeeping_fn , sconn ) ) ) {
2009-01-22 14:36:42 +03:00
DEBUG ( 0 , ( " Could not add housekeeping event \n " ) ) ;
exit ( 1 ) ;
}
# ifdef CLUSTER_SUPPORT
if ( lp_clustering ( ) ) {
/*
* We need to tell ctdb about our client ' s TCP
* connection , so that for failover ctdbd can send
* tickle acks , triggering a reconnection by the
* client .
*/
struct sockaddr_storage srv , clnt ;
2010-09-27 04:15:18 +04:00
if ( client_get_tcp_info ( sconn - > sock , & srv , & clnt ) = = 0 ) {
2009-01-22 14:36:42 +03:00
NTSTATUS status ;
2010-08-28 19:16:08 +04:00
status = smbd_register_ips ( sconn , & srv , & clnt ) ;
2009-01-22 14:36:42 +03:00
if ( ! NT_STATUS_IS_OK ( status ) ) {
DEBUG ( 0 , ( " ctdbd_register_ips failed: %s \n " ,
nt_errstr ( status ) ) ) ;
}
} else
{
DEBUG ( 0 , ( " Unable to get tcp info for "
" CTDB_CONTROL_TCP_CLIENT: %s \n " ,
strerror ( errno ) ) ) ;
}
}
# endif
2010-08-08 20:47:02 +04:00
sconn - > nbt . got_session = false ;
2009-05-26 17:20:36 +04:00
2012-05-28 11:28:04 +04:00
sconn - > smb1 . negprot . max_recv = MIN ( lp_max_xmit ( ) , BUFFER_SIZE ) ;
2009-01-22 14:36:42 +03:00
2010-08-08 20:47:02 +04:00
sconn - > smb1 . sessions . done_sesssetup = false ;
sconn - > smb1 . sessions . max_send = BUFFER_SIZE ;
sconn - > smb1 . sessions . last_session_tag = UID_FIELD_INVALID ;
2009-05-26 17:21:16 +04:00
2010-08-08 20:47:02 +04:00
if ( ! init_dptrs ( sconn ) ) {
2009-08-06 14:15:51 +04:00
exit_server ( " init_dptrs() failed " ) ;
}
2009-05-27 13:15:44 +04:00
2011-08-08 20:39:56 +04:00
sconn - > smb1 . fde = event_add_fd ( ev_ctx ,
2010-08-08 20:47:02 +04:00
sconn ,
2010-08-15 13:43:46 +04:00
sconn - > sock ,
2009-05-26 12:48:12 +04:00
EVENT_FD_READ ,
smbd_server_connection_handler ,
2010-08-08 20:47:02 +04:00
sconn ) ;
if ( ! sconn - > smb1 . fde ) {
2009-01-08 17:38:47 +03:00
exit_server ( " failed to create smbd_server_connection fde " ) ;
}
2011-12-15 17:45:56 +04:00
sconn - > conn - > local_address = sconn - > local_address ;
sconn - > conn - > remote_address = sconn - > remote_address ;
sconn - > conn - > remote_hostname = sconn - > remote_hostname ;
sconn - > conn - > protocol = PROTOCOL_NONE ;
2009-01-22 14:36:42 +03:00
TALLOC_FREE ( frame ) ;
2012-06-20 10:53:10 +04:00
tevent_set_trace_callback ( ev_ctx , smbd_tevent_trace_callback , conn ) ;
2012-06-08 16:07:51 +04:00
totally rewrote the async signal, notification and oplock notification
handling in Samba. This was needed due to several limitations and
races in the previous code - as a side effect the new code is much
cleaner :)
in summary:
- changed sys_select() to avoid a signal/select race condition. It is a
rare race but once we have signals doing notification and oplocks it
is important.
- changed our main processing loop to take advantage of the new
sys_select semantics
- split the notify code into implementaion dependent and general
parts. Added the following structure that defines an implementation:
struct cnotify_fns {
void * (*register_notify)(connection_struct *conn, char *path, uint32 flags);
BOOL (*check_notify)(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *data, time_t t);
void (*remove_notify)(void *data);
};
then I wrote two implementations, one using hash/poll (like our old
code) and the other using the new Linux kernel change notify. It
should be easy to add other change notify implementations by creating
a sructure of the above type.
- fixed a bug in change notify where we were returning the wrong error
code.
- rewrote the core change notify code to be much simpler
- moved to real-time signals for leases and change notify
Amazingly, it all seems to work. I was very surprised!
(This used to be commit 44766c39e0027c762bee8b33b12c621c109a3267)
2000-06-12 19:53:31 +04:00
while ( True ) {
2009-01-22 14:36:42 +03:00
frame = talloc_stackframe_pool ( 8192 ) ;
1998-08-20 23:28:37 +04:00
2007-10-31 02:22:24 +03:00
errno = 0 ;
2012-02-17 04:14:14 +04:00
if ( tevent_loop_once ( ev_ctx ) = = - 1 ) {
if ( errno ! = EINTR ) {
DEBUG ( 3 , ( " tevent_loop_once failed: %s, "
" exiting \n " , strerror ( errno ) ) ) ;
break ;
}
totally rewrote the async signal, notification and oplock notification
handling in Samba. This was needed due to several limitations and
races in the previous code - as a side effect the new code is much
cleaner :)
in summary:
- changed sys_select() to avoid a signal/select race condition. It is a
rare race but once we have signals doing notification and oplocks it
is important.
- changed our main processing loop to take advantage of the new
sys_select semantics
- split the notify code into implementaion dependent and general
parts. Added the following structure that defines an implementation:
struct cnotify_fns {
void * (*register_notify)(connection_struct *conn, char *path, uint32 flags);
BOOL (*check_notify)(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *data, time_t t);
void (*remove_notify)(void *data);
};
then I wrote two implementations, one using hash/poll (like our old
code) and the other using the new Linux kernel change notify. It
should be easy to add other change notify implementations by creating
a sructure of the above type.
- fixed a bug in change notify where we were returning the wrong error
code.
- rewrote the core change notify code to be much simpler
- moved to real-time signals for leases and change notify
Amazingly, it all seems to work. I was very surprised!
(This used to be commit 44766c39e0027c762bee8b33b12c621c109a3267)
2000-06-12 19:53:31 +04:00
}
2007-08-30 23:48:31 +04:00
TALLOC_FREE ( frame ) ;
totally rewrote the async signal, notification and oplock notification
handling in Samba. This was needed due to several limitations and
races in the previous code - as a side effect the new code is much
cleaner :)
in summary:
- changed sys_select() to avoid a signal/select race condition. It is a
rare race but once we have signals doing notification and oplocks it
is important.
- changed our main processing loop to take advantage of the new
sys_select semantics
- split the notify code into implementaion dependent and general
parts. Added the following structure that defines an implementation:
struct cnotify_fns {
void * (*register_notify)(connection_struct *conn, char *path, uint32 flags);
BOOL (*check_notify)(connection_struct *conn, uint16 vuid, char *path, uint32 flags, void *data, time_t t);
void (*remove_notify)(void *data);
};
then I wrote two implementations, one using hash/poll (like our old
code) and the other using the new Linux kernel change notify. It
should be easy to add other change notify implementations by creating
a sructure of the above type.
- fixed a bug in change notify where we were returning the wrong error
code.
- rewrote the core change notify code to be much simpler
- moved to real-time signals for leases and change notify
Amazingly, it all seems to work. I was very surprised!
(This used to be commit 44766c39e0027c762bee8b33b12c621c109a3267)
2000-06-12 19:53:31 +04:00
}
2009-01-22 14:36:42 +03:00
exit_server_cleanly ( NULL ) ;
1998-08-17 17:11:34 +04:00
}
2009-01-31 01:44:21 +03:00
bool req_is_in_chain ( struct smb_request * req )
{
2011-05-05 21:41:59 +04:00
if ( req - > vwv ! = ( const uint16_t * ) ( req - > inbuf + smb_vwv ) ) {
2009-01-31 01:44:21 +03:00
/*
* We ' re right now handling a subsequent request , so we must
* be in a chain
*/
return true ;
}
if ( ! is_andx_req ( req - > cmd ) ) {
return false ;
}
if ( req - > wct < 2 ) {
/*
* Okay , an illegal request , but definitely not chained : - )
*/
return false ;
}
return ( CVAL ( req - > vwv + 0 , 0 ) ! = 0xFF ) ;
}