1998-03-15 05:37:52 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1998-03-15 05:37:52 +03:00
connection claim routines
Copyright ( C ) Andrew Tridgell 1998
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
2000-01-03 02:00:27 +03:00
static TDB_CONTEXT * tdb ;
1998-03-15 05:37:52 +03:00
2000-12-15 04:02:11 +03:00
/****************************************************************************
Return the connection tdb context ( used for message send all ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
TDB_CONTEXT * conn_tdb_ctx ( void )
{
2002-09-25 19:19:00 +04:00
if ( ! tdb )
2004-06-04 21:26:09 +04:00
tdb = tdb_open_log ( lock_path ( " connections.tdb " ) , 0 , TDB_CLEAR_IF_FIRST | TDB_DEFAULT ,
O_RDWR | O_CREAT , 0644 ) ;
2002-08-17 19:27:10 +04:00
2000-12-15 04:02:11 +03:00
return tdb ;
}
2003-01-03 11:28:12 +03:00
static void make_conn_key ( connection_struct * conn , const char * name , TDB_DATA * pkbuf , struct connections_key * pkey )
2002-09-25 19:19:00 +04:00
{
ZERO_STRUCTP ( pkey ) ;
2005-09-30 21:13:37 +04:00
pkey - > pid = procid_self ( ) ;
2002-09-25 19:19:00 +04:00
pkey - > cnum = conn ? conn - > cnum : - 1 ;
fstrcpy ( pkey - > name , name ) ;
2003-05-31 05:48:59 +04:00
# ifdef DEVELOPER
2003-05-31 06:03:58 +04:00
/* valgrind fixer... */
2003-05-31 05:48:59 +04:00
{
size_t sl = strlen ( pkey - > name ) ;
if ( sizeof ( fstring ) - sl )
memset ( & pkey - > name [ sl ] , ' \0 ' , sizeof ( fstring ) - sl ) ;
}
# endif
2002-09-25 19:19:00 +04:00
2007-03-29 13:35:51 +04:00
pkbuf - > dptr = ( uint8 * ) pkey ;
2002-09-25 19:19:00 +04:00
pkbuf - > dsize = sizeof ( * pkey ) ;
}
1999-12-21 07:54:30 +03:00
/****************************************************************************
2001-05-14 10:15:46 +04:00
Delete a connection record .
1999-12-21 07:54:30 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-05-14 10:15:46 +04:00
2003-01-03 11:28:12 +03:00
BOOL yield_connection ( connection_struct * conn , const char * name )
1999-12-21 07:54:30 +03:00
{
struct connections_key key ;
TDB_DATA kbuf ;
1998-03-15 05:37:52 +03:00
2002-09-25 19:19:00 +04:00
if ( ! tdb )
return False ;
1998-03-15 05:37:52 +03:00
1999-12-21 07:54:30 +03:00
DEBUG ( 3 , ( " Yielding connection to %s \n " , name ) ) ;
1998-03-15 05:37:52 +03:00
2002-09-25 19:19:00 +04:00
make_conn_key ( conn , name , & kbuf , & key ) ;
1999-12-21 07:54:30 +03:00
2001-06-09 00:26:46 +04:00
if ( tdb_delete ( tdb , kbuf ) ! = 0 ) {
2001-10-16 12:39:43 +04:00
int dbg_lvl = ( ! conn & & ( tdb_error ( tdb ) = = TDB_ERR_NOEXIST ) ) ? 3 : 0 ;
DEBUG ( dbg_lvl , ( " yield_connection: tdb_delete for name %s failed with error %s. \n " ,
name , tdb_errorstr ( tdb ) ) ) ;
2001-06-09 00:26:46 +04:00
return ( False ) ;
}
2000-01-12 06:09:17 +03:00
1998-03-15 05:37:52 +03:00
return ( True ) ;
}
2001-05-14 10:15:46 +04:00
struct count_stat {
pid_t mypid ;
int curr_connections ;
2006-07-11 22:01:26 +04:00
const char * name ;
2001-05-15 04:53:15 +04:00
BOOL Clear ;
2001-05-14 10:15:46 +04:00
} ;
/****************************************************************************
Count the entries belonging to a service in the connection db .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int count_fn ( TDB_CONTEXT * the_tdb , TDB_DATA kbuf , TDB_DATA dbuf , void * udp )
{
struct connections_data crec ;
struct count_stat * cs = ( struct count_stat * ) udp ;
2007-04-21 01:09:44 +04:00
if ( dbuf . dsize ! = sizeof ( crec ) ) {
2001-05-15 22:12:02 +04:00
return 0 ;
2007-04-21 01:09:44 +04:00
}
2001-05-15 22:12:02 +04:00
2001-05-14 10:15:46 +04:00
memcpy ( & crec , dbuf . dptr , sizeof ( crec ) ) ;
2007-04-21 01:09:44 +04:00
if ( crec . cnum = = - 1 ) {
2001-05-14 10:15:46 +04:00
return 0 ;
2007-04-21 01:09:44 +04:00
}
2001-05-14 10:15:46 +04:00
2001-05-17 04:24:34 +04:00
/* If the pid was not found delete the entry from connections.tdb */
if ( cs - > Clear & & ! process_exists ( crec . pid ) & & ( errno = = ESRCH ) ) {
2005-09-30 21:13:37 +04:00
DEBUG ( 2 , ( " pid %s doesn't exist - deleting connections %d [%s] \n " ,
2007-04-16 23:10:16 +04:00
procid_str_static ( & crec . pid ) , crec . cnum , crec . servicename ) ) ;
2001-06-09 00:26:46 +04:00
if ( tdb_delete ( the_tdb , kbuf ) ! = 0 )
DEBUG ( 0 , ( " count_fn: tdb_delete failed with error %s \n " , tdb_errorstr ( tdb ) ) ) ;
2001-05-14 10:15:46 +04:00
return 0 ;
}
2007-04-21 01:09:44 +04:00
if ( cs - > name ) {
/* We are counting all the connections to a given share. */
if ( strequal ( crec . servicename , cs - > name ) ) {
cs - > curr_connections + + ;
}
} else {
/* We are counting all the connections. Static registrations
* like the lpq backgroud process and the smbd daemon process
* have a cnum of - 1 , so won ' t be counted here .
*/
2001-05-14 10:15:46 +04:00
cs - > curr_connections + + ;
2007-04-21 01:09:44 +04:00
}
2001-05-14 10:15:46 +04:00
return 0 ;
}
1998-03-15 05:37:52 +03:00
1999-12-21 07:54:30 +03:00
/****************************************************************************
2001-05-14 10:15:46 +04:00
Claim an entry in the connections database .
1998-03-15 05:37:52 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-05-14 10:15:46 +04:00
2006-07-11 22:01:26 +04:00
int count_current_connections ( const char * sharename , BOOL clear )
1998-03-15 05:37:52 +03:00
{
2006-07-11 22:01:26 +04:00
struct count_stat cs ;
2002-09-25 19:19:00 +04:00
2006-07-11 22:01:26 +04:00
cs . mypid = sys_getpid ( ) ;
cs . curr_connections = 0 ;
cs . name = sharename ;
cs . Clear = clear ;
2001-05-14 10:15:46 +04:00
/*
2006-07-11 22:01:26 +04:00
* This has a race condition , but locking the chain before hand is worse
* as it leads to deadlock .
2001-05-14 10:15:46 +04:00
*/
2006-07-11 22:01:26 +04:00
if ( tdb_traverse ( tdb , count_fn , & cs ) = = - 1 ) {
2007-04-21 01:09:44 +04:00
DEBUG ( 0 , ( " count_current_connections: traverse of connections.tdb failed with error %s \n " ,
2006-07-11 22:01:26 +04:00
tdb_errorstr ( tdb ) ) ) ;
2007-04-21 01:09:44 +04:00
DEBUGADD ( 0 , ( " count_current_connections: connection count of %d might not be accurate " ,
cs . curr_connections ) ) ;
2006-07-11 22:01:26 +04:00
}
2007-04-21 01:09:44 +04:00
/* If the traverse failed part-way through, we at least return
* as many connections as we had already counted . If it failed
* right at the start , we will return 0 , which is about all we
* can do anywway .
*/
2006-07-11 22:01:26 +04:00
return cs . curr_connections ;
}
2001-05-14 10:15:46 +04:00
2007-04-21 01:09:44 +04:00
/****************************************************************************
Count the number of connections open across all shares .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
int count_all_current_connections ( void )
{
return count_current_connections ( NULL , True /* clear stale entries */ ) ;
}
2006-07-11 22:01:26 +04:00
/****************************************************************************
Claim an entry in the connections database .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2001-05-14 10:15:46 +04:00
2006-07-11 22:01:26 +04:00
BOOL claim_connection ( connection_struct * conn , const char * name , int max_connections , BOOL Clear , uint32 msg_flags )
{
struct connections_key key ;
struct connections_data crec ;
TDB_DATA kbuf , dbuf ;
2001-09-19 11:06:34 +04:00
2006-07-11 22:01:26 +04:00
if ( ! tdb ) {
if ( ( tdb = conn_tdb_ctx ( ) ) = = NULL ) {
2001-09-19 11:06:34 +04:00
return False ;
2001-05-14 10:15:46 +04:00
}
2006-07-11 22:01:26 +04:00
}
/*
* Enforce the max connections parameter .
*/
2001-05-14 10:15:46 +04:00
2006-07-11 22:01:26 +04:00
if ( max_connections > 0 ) {
int curr_connections ;
curr_connections = count_current_connections ( lp_servicename ( SNUM ( conn ) ) , True ) ;
if ( curr_connections > = max_connections ) {
2001-05-14 10:15:46 +04:00
DEBUG ( 1 , ( " claim_connection: Max connections (%d) exceeded for %s \n " ,
max_connections , name ) ) ;
2001-09-19 11:06:34 +04:00
return False ;
2001-05-14 10:15:46 +04:00
}
}
1998-03-15 05:37:52 +03:00
1999-12-21 07:54:30 +03:00
DEBUG ( 5 , ( " claiming %s %d \n " , name , max_connections ) ) ;
2002-09-25 19:19:00 +04:00
make_conn_key ( conn , name , & kbuf , & key ) ;
1998-03-15 05:37:52 +03:00
/* fill in the crec */
1999-12-21 07:54:30 +03:00
ZERO_STRUCT ( crec ) ;
1998-03-15 05:37:52 +03:00
crec . magic = 0x280267 ;
2005-09-30 21:13:37 +04:00
crec . pid = procid_self ( ) ;
1999-12-21 07:54:30 +03:00
crec . cnum = conn ? conn - > cnum : - 1 ;
1998-08-14 21:38:29 +04:00
if ( conn ) {
crec . uid = conn - > uid ;
crec . gid = conn - > gid ;
2007-04-16 23:10:16 +04:00
safe_strcpy ( crec . servicename ,
lp_servicename ( SNUM ( conn ) ) , sizeof ( crec . servicename ) - 1 ) ;
1998-03-15 05:37:52 +03:00
}
crec . start = time ( NULL ) ;
2002-09-25 19:19:00 +04:00
crec . bcast_msg_flags = msg_flags ;
1998-03-15 05:37:52 +03:00
2003-03-22 16:47:42 +03:00
safe_strcpy ( crec . machine , get_remote_machine_name ( ) , sizeof ( crec . machine ) - 1 ) ;
safe_strcpy ( crec . addr , conn ? conn - > client_address : client_addr ( ) , sizeof ( crec . addr ) - 1 ) ;
1998-03-15 05:37:52 +03:00
2007-03-29 13:35:51 +04:00
dbuf . dptr = ( uint8 * ) & crec ;
1999-12-21 07:54:30 +03:00
dbuf . dsize = sizeof ( crec ) ;
2001-05-24 01:33:43 +04:00
if ( tdb_store ( tdb , kbuf , dbuf , TDB_REPLACE ) ! = 0 ) {
DEBUG ( 0 , ( " claim_connection: tdb_store failed with error %s. \n " ,
tdb_errorstr ( tdb ) ) ) ;
2001-09-19 11:06:34 +04:00
return False ;
2001-05-24 01:33:43 +04:00
}
1999-12-21 07:54:30 +03:00
2001-09-19 11:06:34 +04:00
return True ;
2001-05-14 22:43:49 +04:00
}
2002-09-25 19:19:00 +04:00
BOOL register_message_flags ( BOOL doreg , uint32 msg_flags )
{
struct connections_key key ;
struct connections_data * pcrec ;
TDB_DATA kbuf , dbuf ;
if ( ! tdb )
return False ;
DEBUG ( 10 , ( " register_message_flags: %s flags 0x%x \n " ,
doreg ? " adding " : " removing " ,
( unsigned int ) msg_flags ) ) ;
make_conn_key ( NULL , " " , & kbuf , & key ) ;
dbuf = tdb_fetch ( tdb , kbuf ) ;
if ( ! dbuf . dptr ) {
2004-11-30 18:55:27 +03:00
DEBUG ( 0 , ( " register_message_flags: tdb_fetch failed: %s \n " ,
tdb_errorstr ( tdb ) ) ) ;
2002-09-25 19:19:00 +04:00
return False ;
}
pcrec = ( struct connections_data * ) dbuf . dptr ;
if ( doreg )
pcrec - > bcast_msg_flags | = msg_flags ;
else
pcrec - > bcast_msg_flags & = ~ msg_flags ;
if ( tdb_store ( tdb , kbuf , dbuf , TDB_REPLACE ) ! = 0 ) {
2004-11-30 18:55:27 +03:00
DEBUG ( 0 , ( " register_message_flags: tdb_store failed: %s. \n " ,
2002-09-25 19:19:00 +04:00
tdb_errorstr ( tdb ) ) ) ;
SAFE_FREE ( dbuf . dptr ) ;
return False ;
}
DEBUG ( 10 , ( " register_message_flags: new flags 0x%x \n " ,
( unsigned int ) pcrec - > bcast_msg_flags ) ) ;
SAFE_FREE ( dbuf . dptr ) ;
return True ;
}
2006-07-11 22:01:26 +04:00
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static TDB_DATA * make_pipe_rec_key ( struct pipe_open_rec * prec )
{
TDB_DATA * kbuf = NULL ;
fstring key_string ;
if ( ! prec )
return NULL ;
if ( ( kbuf = TALLOC_P ( prec , TDB_DATA ) ) = = NULL ) {
return NULL ;
}
snprintf ( key_string , sizeof ( key_string ) , " %s/%d/%d " ,
prec - > name , procid_to_pid ( & prec - > pid ) , prec - > pnum ) ;
2007-03-29 12:24:15 +04:00
* kbuf = string_term_tdb_data ( talloc_strdup ( prec , key_string ) ) ;
if ( kbuf - > dptr = = NULL )
2006-07-11 22:01:26 +04:00
return NULL ;
2007-03-29 12:24:15 +04:00
2006-07-11 22:01:26 +04:00
return kbuf ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void fill_pipe_open_rec ( struct pipe_open_rec * prec , smb_np_struct * p )
{
prec - > pid = pid_to_procid ( sys_getpid ( ) ) ;
prec - > pnum = p - > pnum ;
prec - > uid = geteuid ( ) ;
fstrcpy ( prec - > name , p - > name ) ;
return ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL store_pipe_opendb ( smb_np_struct * p )
{
struct pipe_open_rec * prec ;
TDB_DATA * key ;
TDB_DATA data ;
TDB_CONTEXT * pipe_tdb ;
BOOL ret = False ;
if ( ( prec = TALLOC_P ( NULL , struct pipe_open_rec ) ) = = NULL ) {
DEBUG ( 0 , ( " store_pipe_opendb: talloc failed! \n " ) ) ;
return False ;
}
fill_pipe_open_rec ( prec , p ) ;
if ( ( key = make_pipe_rec_key ( prec ) ) = = NULL ) {
goto done ;
}
2007-03-29 13:35:51 +04:00
data . dptr = ( uint8 * ) prec ;
2006-07-11 22:01:26 +04:00
data . dsize = sizeof ( struct pipe_open_rec ) ;
if ( ( pipe_tdb = conn_tdb_ctx ( ) ) = = NULL ) {
goto done ;
}
ret = ( tdb_store ( pipe_tdb , * key , data , TDB_REPLACE ) ! = - 1 ) ;
done :
TALLOC_FREE ( prec ) ;
return ret ;
}
/*********************************************************************
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL delete_pipe_opendb ( smb_np_struct * p )
{
struct pipe_open_rec * prec ;
TDB_DATA * key ;
TDB_CONTEXT * pipe_tdb ;
BOOL ret = False ;
if ( ( prec = TALLOC_P ( NULL , struct pipe_open_rec ) ) = = NULL ) {
DEBUG ( 0 , ( " store_pipe_opendb: talloc failed! \n " ) ) ;
return False ;
}
fill_pipe_open_rec ( prec , p ) ;
if ( ( key = make_pipe_rec_key ( prec ) ) = = NULL ) {
goto done ;
}
if ( ( pipe_tdb = conn_tdb_ctx ( ) ) = = NULL ) {
goto done ;
}
ret = ( tdb_delete ( pipe_tdb , * key ) ! = - 1 ) ;
done :
TALLOC_FREE ( prec ) ;
return ret ;
}