1998-08-17 10:13:32 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-08-17 10:13:32 +04:00
Manage connections_struct structures
Copyright ( C ) Andrew Tridgell 1998
2002-08-17 19:27:10 +04:00
Copyright ( C ) Alexander Bokovoy 2002
1998-08-17 10:13:32 +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 10:13:32 +04:00
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
2007-07-10 04:52:41 +04:00
along with this program . If not , see < http : //www.gnu.org/licenses/>.
1998-08-17 10:13:32 +04:00
*/
# include "includes.h"
2009-01-08 14:03:45 +03:00
# include "smbd/globals.h"
1998-08-17 10:13:32 +04:00
2003-12-11 23:00:16 +03:00
/* The connections bitmap is expanded in increments of BITMAP_BLOCK_SZ. The
* maximum size of the bitmap is the largest positive integer , but you will hit
* the " max connections " limit , looong before that .
*/
# define BITMAP_BLOCK_SZ 128
1998-08-17 10:13:32 +04:00
/****************************************************************************
init the conn structures
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-27 13:15:44 +04:00
void conn_init ( struct smbd_server_connection * sconn )
1998-08-17 10:13:32 +04:00
{
2009-05-27 13:15:44 +04:00
sconn - > smb1 . tcons . Connections = NULL ;
sconn - > smb1 . tcons . num_open = 0 ;
2010-03-28 16:19:17 +04:00
sconn - > smb1 . tcons . bmap = bitmap_talloc ( sconn , BITMAP_BLOCK_SZ ) ;
1998-08-17 10:13:32 +04:00
}
/****************************************************************************
return the number of open connections
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-27 13:15:44 +04:00
int conn_num_open ( struct smbd_server_connection * sconn )
1998-08-17 10:13:32 +04:00
{
2009-05-27 13:15:44 +04:00
return sconn - > smb1 . tcons . num_open ;
1998-08-17 10:13:32 +04:00
}
/****************************************************************************
check if a snum is in use
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool conn_snum_used ( int snum )
1998-08-17 10:13:32 +04:00
{
2009-05-27 13:15:44 +04:00
struct smbd_server_connection * sconn = smbd_server_conn ;
1998-08-17 10:13:32 +04:00
connection_struct * conn ;
2009-05-27 13:15:44 +04:00
for ( conn = sconn - > smb1 . tcons . Connections ; conn ; conn = conn - > next ) {
2006-07-11 22:01:26 +04:00
if ( conn - > params - > service = = snum ) {
1998-08-17 10:13:32 +04:00
return ( True ) ;
}
}
return ( False ) ;
}
/****************************************************************************
2008-05-14 01:01:19 +04:00
Find a conn given a cnum .
1998-08-17 10:13:32 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2008-05-14 01:01:19 +04:00
2009-05-27 13:15:44 +04:00
connection_struct * conn_find ( struct smbd_server_connection * sconn , unsigned cnum )
1998-08-17 10:13:32 +04:00
{
1998-08-17 10:47:53 +04:00
int count = 0 ;
1998-08-17 10:13:32 +04:00
connection_struct * conn ;
2009-05-27 13:15:44 +04:00
for ( conn = sconn - > smb1 . tcons . Connections ; conn ; conn = conn - > next , count + + ) {
1998-08-17 10:47:53 +04:00
if ( conn - > cnum = = cnum ) {
if ( count > 10 ) {
2009-05-27 13:15:44 +04:00
DLIST_PROMOTE ( sconn - > smb1 . tcons . Connections ,
conn ) ;
1998-08-17 10:47:53 +04:00
}
return conn ;
}
1998-08-17 10:13:32 +04:00
}
return NULL ;
}
/****************************************************************************
find first available connection slot , starting from a random position .
The randomisation stops problems with the server dieing and clients
thinking the server is still available .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-27 13:15:44 +04:00
connection_struct * conn_new ( struct smbd_server_connection * sconn )
1998-08-17 10:13:32 +04:00
{
connection_struct * conn ;
int i ;
2003-12-11 23:00:16 +03:00
int find_offset = 1 ;
1998-08-17 10:13:32 +04:00
2010-06-10 06:12:02 +04:00
if ( sconn - > using_smb2 ) {
2009-05-27 20:28:56 +04:00
if ( ! ( conn = TALLOC_ZERO_P ( NULL , connection_struct ) ) | |
! ( conn - > params = TALLOC_P ( conn , struct share_params ) ) ) {
DEBUG ( 0 , ( " TALLOC_ZERO() failed! \n " ) ) ;
TALLOC_FREE ( conn ) ;
return NULL ;
}
2009-08-06 15:22:33 +04:00
conn - > sconn = sconn ;
2009-05-27 20:28:56 +04:00
return conn ;
}
2003-12-11 23:00:16 +03:00
find_again :
2009-05-27 13:15:44 +04:00
i = bitmap_find ( sconn - > smb1 . tcons . bmap , find_offset ) ;
1998-08-17 10:13:32 +04:00
if ( i = = - 1 ) {
2003-12-11 23:00:16 +03:00
/* Expand the connections bitmap. */
2009-05-27 13:15:44 +04:00
int oldsz = sconn - > smb1 . tcons . bmap - > n ;
int newsz = sconn - > smb1 . tcons . bmap - > n +
BITMAP_BLOCK_SZ ;
2003-12-11 23:00:16 +03:00
struct bitmap * nbmap ;
2006-10-18 07:34:31 +04:00
if ( newsz < = oldsz ) {
2003-12-11 23:00:16 +03:00
/* Integer wrap. */
DEBUG ( 0 , ( " ERROR! Out of connection structures \n " ) ) ;
return NULL ;
}
DEBUG ( 4 , ( " resizing connections bitmap from %d to %d \n " ,
oldsz , newsz ) ) ;
2010-03-28 16:19:17 +04:00
nbmap = bitmap_talloc ( sconn , newsz ) ;
2006-06-17 03:04:13 +04:00
if ( ! nbmap ) {
DEBUG ( 0 , ( " ERROR! malloc fail. \n " ) ) ;
return NULL ;
}
2003-12-11 23:00:16 +03:00
2009-05-27 13:15:44 +04:00
bitmap_copy ( nbmap , sconn - > smb1 . tcons . bmap ) ;
2010-03-28 16:19:17 +04:00
TALLOC_FREE ( sconn - > smb1 . tcons . bmap ) ;
2003-12-11 23:00:16 +03:00
2009-05-27 13:15:44 +04:00
sconn - > smb1 . tcons . bmap = nbmap ;
2003-12-11 23:00:16 +03:00
find_offset = oldsz ; /* Start next search in the new portion. */
goto find_again ;
1998-08-17 10:13:32 +04:00
}
2006-10-18 07:34:31 +04:00
/* The bitmap position is used below as the connection number
* conn - > cnum ) . This ends up as the TID field in the SMB header ,
* which is limited to 16 bits ( we skip 0xffff which is the
* NULL TID ) .
*/
if ( i > 65534 ) {
DEBUG ( 0 , ( " Maximum connection limit reached \n " ) ) ;
return NULL ;
}
2008-04-28 12:31:49 +04:00
if ( ! ( conn = TALLOC_ZERO_P ( NULL , connection_struct ) ) | |
! ( conn - > params = TALLOC_P ( conn , struct share_params ) ) ) {
2007-04-28 03:18:41 +04:00
DEBUG ( 0 , ( " TALLOC_ZERO() failed! \n " ) ) ;
2008-04-28 12:31:49 +04:00
TALLOC_FREE ( conn ) ;
2003-05-12 03:34:18 +04:00
return NULL ;
}
2009-08-06 15:22:33 +04:00
conn - > sconn = sconn ;
1998-08-17 10:13:32 +04:00
conn - > cnum = i ;
2009-03-04 03:08:56 +03:00
conn - > force_group_gid = ( gid_t ) - 1 ;
1998-08-17 10:13:32 +04:00
2009-05-27 13:15:44 +04:00
bitmap_set ( sconn - > smb1 . tcons . bmap , i ) ;
1998-08-17 10:13:32 +04:00
2009-05-27 13:15:44 +04:00
sconn - > smb1 . tcons . num_open + + ;
1998-08-17 10:13:32 +04:00
2000-01-16 14:18:04 +03:00
string_set ( & conn - > connectpath , " " ) ;
string_set ( & conn - > origpath , " " ) ;
1998-08-17 10:13:32 +04:00
2009-05-27 13:15:44 +04:00
DLIST_ADD ( sconn - > smb1 . tcons . Connections , conn ) ;
1998-08-17 10:13:32 +04:00
return conn ;
}
/****************************************************************************
2006-04-15 08:07:10 +04:00
Close all conn structures .
2008-08-08 16:34:59 +04:00
return true if any were closed
1998-08-17 10:13:32 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-05-27 13:15:44 +04:00
bool conn_close_all ( struct smbd_server_connection * sconn )
1998-08-17 10:13:32 +04:00
{
2010-06-10 06:12:02 +04:00
if ( sconn - > using_smb2 ) {
2010-02-25 05:11:07 +03:00
/* SMB2 */
if ( sconn - > smb2 . sessions . list & &
sconn - > smb2 . sessions . list - > tcons . list ) {
2010-05-07 17:54:16 +04:00
struct smbd_smb2_tcon * tcon , * tc_next ;
for ( tcon = sconn - > smb2 . sessions . list - > tcons . list ;
tcon ; tcon = tc_next ) {
tc_next = tcon - > next ;
TALLOC_FREE ( tcon ) ;
}
2010-02-25 05:11:07 +03:00
return true ;
}
return false ;
} else {
/* SMB1 */
connection_struct * conn , * next ;
bool ret = false ;
for ( conn = sconn - > smb1 . tcons . Connections ; conn ; conn = next ) {
next = conn - > next ;
set_current_service ( conn , 0 , True ) ;
close_cnum ( conn , conn - > vuid ) ;
ret = true ;
}
return ret ;
1998-08-17 10:13:32 +04:00
}
}
/****************************************************************************
2003-01-17 09:34:22 +03:00
Idle inactive connections .
1998-08-17 10:13:32 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-01-17 09:34:22 +03:00
2009-05-27 13:15:44 +04:00
bool conn_idle_all ( struct smbd_server_connection * sconn , time_t t )
1998-08-17 10:13:32 +04:00
{
2007-03-18 13:09:16 +03:00
int deadtime = lp_deadtime ( ) * 60 ;
2007-03-18 16:19:40 +03:00
connection_struct * conn ;
1998-08-17 10:13:32 +04:00
2007-03-18 13:09:16 +03:00
if ( deadtime < = 0 )
deadtime = DEFAULT_SMBD_TIMEOUT ;
2009-05-27 13:15:44 +04:00
for ( conn = sconn - > smb1 . tcons . Connections ; conn ; conn = conn - > next ) {
2007-03-18 16:19:40 +03:00
time_t age = t - conn - > lastused ;
2006-04-15 08:07:10 +04:00
/* Update if connection wasn't idle. */
if ( conn - > lastused ! = conn - > lastused_count ) {
conn - > lastused = t ;
2006-11-15 04:06:45 +03:00
conn - > lastused_count = t ;
2006-04-15 08:07:10 +04:00
}
1998-08-17 10:13:32 +04:00
/* close dirptrs on connections that are idle */
2007-03-18 16:19:40 +03:00
if ( age > DPTR_IDLE_TIMEOUT ) {
1998-08-17 10:13:32 +04:00
dptr_idlecnum ( conn ) ;
2006-04-15 08:07:10 +04:00
}
1998-08-17 10:13:32 +04:00
2007-03-18 16:19:40 +03:00
if ( conn - > num_files_open > 0 | | age < deadtime ) {
return False ;
2006-04-15 08:07:10 +04:00
}
1998-08-17 10:13:32 +04:00
}
2003-01-17 09:34:22 +03:00
/*
* Check all pipes for any open handles . We cannot
* idle with a handle open .
*/
2010-06-07 22:08:05 +04:00
if ( check_open_pipes ( ) ) {
return False ;
2007-03-18 16:19:40 +03:00
}
2010-06-07 22:08:05 +04:00
2007-03-18 16:19:40 +03:00
return True ;
1998-08-17 10:13:32 +04:00
}
2002-09-25 19:19:00 +04:00
/****************************************************************************
2004-02-13 22:05:25 +03:00
Clear a vuid out of the validity cache , and as the ' owner ' of a connection .
2002-09-25 19:19:00 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-02-13 22:05:25 +03:00
2009-05-27 13:15:44 +04:00
void conn_clear_vuid_caches ( struct smbd_server_connection * sconn , uint16_t vuid )
2002-09-25 19:19:00 +04:00
{
connection_struct * conn ;
2009-05-27 13:15:44 +04:00
for ( conn = sconn - > smb1 . tcons . Connections ; conn ; conn = conn - > next ) {
2002-09-25 19:19:00 +04:00
if ( conn - > vuid = = vuid ) {
conn - > vuid = UID_FIELD_INVALID ;
}
2008-06-14 18:59:07 +04:00
conn_clear_vuid_cache ( conn , vuid ) ;
2002-09-25 19:19:00 +04:00
}
}
1998-08-17 10:13:32 +04:00
/****************************************************************************
2005-08-03 03:55:38 +04:00
Free a conn structure - internal part .
1998-08-17 10:13:32 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-08-04 02:38:43 +04:00
2009-08-07 13:48:03 +04:00
static void conn_free_internal ( connection_struct * conn )
1998-08-17 10:13:32 +04:00
{
2009-08-07 13:48:03 +04:00
vfs_handle_struct * handle = NULL , * thandle = NULL ;
2006-12-15 03:49:12 +03:00
struct trans_state * state = NULL ;
2002-08-17 19:27:10 +04:00
2000-04-29 01:09:26 +04:00
/* Free vfs_connection_struct */
2003-05-12 03:34:18 +04:00
handle = conn - > vfs_handles ;
2002-08-17 19:27:10 +04:00
while ( handle ) {
thandle = handle - > next ;
2008-10-02 00:15:54 +04:00
DLIST_REMOVE ( conn - > vfs_handles , handle ) ;
2003-05-12 03:34:18 +04:00
if ( handle - > free_data )
handle - > free_data ( & handle - > data ) ;
2002-08-17 19:27:10 +04:00
handle = thandle ;
2000-04-29 01:09:26 +04:00
}
2006-12-15 03:49:12 +03:00
/* Free any pending transactions stored on this conn. */
for ( state = conn - > pending_trans ; state ; state = state - > next ) {
/* state->setup is a talloc child of state. */
SAFE_FREE ( state - > param ) ;
SAFE_FREE ( state - > data ) ;
}
1998-08-17 10:13:32 +04:00
free_namearray ( conn - > veto_list ) ;
free_namearray ( conn - > hide_list ) ;
free_namearray ( conn - > veto_oplock_list ) ;
2007-10-11 00:34:30 +04:00
free_namearray ( conn - > aio_write_behind_list ) ;
1998-08-17 10:13:32 +04:00
string_free ( & conn - > connectpath ) ;
string_free ( & conn - > origpath ) ;
1998-09-05 17:24:20 +04:00
ZERO_STRUCTP ( conn ) ;
2008-04-28 12:31:49 +04:00
talloc_destroy ( conn ) ;
1998-08-17 10:13:32 +04:00
}
2001-06-20 07:05:09 +04:00
2005-08-03 03:55:38 +04:00
/****************************************************************************
Free a conn structure .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2009-08-06 15:22:33 +04:00
void conn_free ( connection_struct * conn )
2005-08-03 03:55:38 +04:00
{
2009-08-06 15:22:33 +04:00
if ( conn - > sconn = = NULL ) {
conn_free_internal ( conn ) ;
return ;
}
2010-06-10 06:12:02 +04:00
if ( conn - > sconn - > using_smb2 ) {
2009-05-27 20:28:56 +04:00
conn_free_internal ( conn ) ;
return ;
}
2009-08-06 15:22:33 +04:00
DLIST_REMOVE ( conn - > sconn - > smb1 . tcons . Connections , conn ) ;
2001-06-20 07:05:09 +04:00
2009-08-06 15:22:33 +04:00
bitmap_clear ( conn - > sconn - > smb1 . tcons . bmap , conn - > cnum ) ;
2007-03-18 16:19:40 +03:00
2009-08-06 15:22:33 +04:00
SMB_ASSERT ( conn - > sconn - > smb1 . tcons . num_open > 0 ) ;
conn - > sconn - > smb1 . tcons . num_open - - ;
2005-08-03 03:55:38 +04:00
conn_free_internal ( conn ) ;
}
2001-06-20 07:05:09 +04:00
/****************************************************************************
receive a smbcontrol message to forcibly unmount a share
the message contains just a share name and all instances of that
share are unmounted
the special sharename ' * ' forces unmount of all shares
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-05-16 18:24:06 +04:00
void msg_force_tdis ( struct messaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
2001-06-20 07:05:09 +04:00
{
2009-05-27 13:15:44 +04:00
struct smbd_server_connection * sconn = smbd_server_conn ;
2001-06-20 07:05:09 +04:00
connection_struct * conn , * next ;
fstring sharename ;
2007-05-16 18:24:06 +04:00
fstrcpy ( sharename , ( const char * ) data - > data ) ;
2001-06-20 07:05:09 +04:00
if ( strcmp ( sharename , " * " ) = = 0 ) {
DEBUG ( 1 , ( " Forcing close of all shares \n " ) ) ;
2009-05-27 13:15:44 +04:00
conn_close_all ( sconn ) ;
2001-06-20 07:05:09 +04:00
return ;
}
2009-05-27 13:15:44 +04:00
for ( conn = sconn - > smb1 . tcons . Connections ; conn ; conn = next ) {
2001-06-20 07:05:09 +04:00
next = conn - > next ;
2006-07-11 22:01:26 +04:00
if ( strequal ( lp_servicename ( SNUM ( conn ) ) , sharename ) ) {
2001-06-20 07:05:09 +04:00
DEBUG ( 1 , ( " Forcing close of share %s cnum=%d \n " ,
sharename , conn - > cnum ) ) ;
2009-08-06 15:22:33 +04:00
close_cnum ( conn , ( uint16 ) - 1 ) ;
2001-06-20 07:05:09 +04:00
}
}
}