2007-10-04 00:43:55 +04:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
2000-01-03 06:24:23 +03:00
handle unexpected packets
Copyright ( C ) Andrew Tridgell 2000
2007-10-04 00:43:55 +04:00
2000-01-03 06:24:23 +03: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
2000-01-03 06:24:23 +03:00
( at your option ) any later version .
2007-10-04 00:43:55 +04:00
2000-01-03 06:24:23 +03: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 .
2007-10-04 00:43:55 +04:00
2000-01-03 06:24:23 +03: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/>.
2007-10-04 00:43:55 +04:00
2000-01-03 06:24:23 +03:00
*/
# include "includes.h"
2010-03-13 22:02:16 +03:00
static struct tdb_wrap * tdbd = NULL ;
2000-01-03 06:24:23 +03:00
2008-03-01 21:54:17 +03:00
/* the key type used in the unexpected packet database */
2000-01-03 06:24:23 +03:00
struct unexpected_key {
enum packet_type packet_type ;
time_t timestamp ;
int count ;
} ;
2010-11-14 07:32:36 +03:00
struct pending_unexpected {
struct pending_unexpected * prev , * next ;
enum packet_type packet_type ;
int id ;
time_t timeout ;
} ;
static struct pending_unexpected * pu_list ;
/****************************************************************************
This function is called when nmbd has received an unexpected packet .
It checks against the list of outstanding packet transaction id ' s
to see if it should be stored in the unexpected . tdb .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct pending_unexpected * find_unexpected_packet ( struct packet_struct * p )
{
struct pending_unexpected * pu ;
if ( ! p ) {
return NULL ;
}
for ( pu = pu_list ; pu ; pu = pu - > next ) {
if ( pu - > packet_type = = p - > packet_type ) {
int id = ( p - > packet_type = = DGRAM_PACKET ) ?
p - > packet . dgram . header . dgm_id :
p - > packet . nmb . header . name_trn_id ;
if ( id = = pu - > id ) {
DEBUG ( 10 , ( " find_unexpected_packet: found packet "
" with id = %d \n " , pu - > id ) ) ;
return pu ;
}
}
}
return NULL ;
}
/****************************************************************************
This function is called when nmbd has been given a packet to send out .
It stores a list of outstanding packet transaction id ' s and the timeout
when they should be removed .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool store_outstanding_send_packet ( struct packet_struct * p )
{
struct pending_unexpected * pu = NULL ;
if ( ! p ) {
return false ;
}
pu = find_unexpected_packet ( p ) ;
if ( pu ) {
/* This is a resend, and we haven't received a
reply yet ! Ignore it . */
return false ;
}
pu = SMB_MALLOC_P ( struct pending_unexpected ) ;
if ( ! pu | | ! p ) {
return false ;
}
ZERO_STRUCTP ( pu ) ;
pu - > packet_type = p - > packet_type ;
pu - > id = ( p - > packet_type = = DGRAM_PACKET ) ?
p - > packet . dgram . header . dgm_id :
p - > packet . nmb . header . name_trn_id ;
pu - > timeout = time ( NULL ) + 15 ;
DLIST_ADD_END ( pu_list , pu , struct pending_unexpected * ) ;
DEBUG ( 10 , ( " store_outstanding_unexpected_packet: storing packet "
" with id = %d \n " , pu - > id ) ) ;
return true ;
}
/****************************************************************************
Return true if this is a reply to a packet we were requested to send .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
bool is_requested_send_packet ( struct packet_struct * p )
{
return ( find_unexpected_packet ( p ) ! = NULL ) ;
}
/****************************************************************************
This function is called when nmbd has received an unexpected packet .
It checks against the list of outstanding packet transaction id ' s
to see if it should be stored in the unexpected . tdb . Don ' t store if
not found .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static bool should_store_unexpected_packet ( struct packet_struct * p )
{
struct pending_unexpected * pu = find_unexpected_packet ( p ) ;
if ( ! pu ) {
return false ;
}
/* Remove the outstanding entry. */
DLIST_REMOVE ( pu_list , pu ) ;
SAFE_FREE ( pu ) ;
return true ;
}
2000-01-03 06:24:23 +03:00
/****************************************************************************
2007-10-04 00:43:55 +04:00
All unexpected packets are passed in here , to be stored in a unexpected
2000-01-03 06:24:23 +03:00
packet database . This allows nmblookup and other tools to receive packets
2008-03-01 21:54:17 +03:00
erroneously sent to the wrong port by broken MS systems .
2007-10-04 00:43:55 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-01-03 06:24:23 +03:00
void unexpected_packet ( struct packet_struct * p )
{
static int count ;
TDB_DATA kbuf , dbuf ;
struct unexpected_key key ;
char buf [ 1024 ] ;
int len = 0 ;
2007-10-04 00:43:55 +04:00
uint32_t enc_ip ;
2000-01-03 06:24:23 +03:00
2010-11-14 07:32:36 +03:00
if ( ! should_store_unexpected_packet ( p ) ) {
DEBUG ( 10 , ( " Not storing unexpected packet \n " ) ) ;
return ;
}
DEBUG ( 10 , ( " unexpected_packet: storing packet \n " ) ) ;
1) added void* state argument to tdb_traverse. guess what! there were
two places i found where it was appropriate to _use_ that third argument,
in locking.c and brlock.c! there was a static traverse_function and
i removed the static variable, typecast it to a void*, passed it to
tdb_traverse and re-cast it back to the traverse_function inside the
tdb_traverse function. this makes the use of tdb_traverse() reentrant,
which is never going to happen, i know, i just don't like to see
statics lying about when there's no need for them.
as i had to do in samba-tng, all uses of tdb_traverse modified to take
the new void* state argument.
2) disabled rpcclient: referring people to use SAMBA_TNG rpcclient.
i don't know how the other samba team members would react if i deleted
rpcclient from cvs main. damn, that code's so old, it's unreal.
20 rpcclient commands, instead of about 70 in SAMBA_TNG.
(This used to be commit 49d7f0afbc1c5425d53019e234d54ddf205c8e9a)
2000-02-04 07:59:31 +03:00
if ( ! tdbd ) {
2010-10-03 01:44:58 +04:00
tdbd = tdb_wrap_open ( NULL , lock_path ( " unexpected.tdb " ) , 0 ,
2010-09-27 16:46:07 +04:00
TDB_CLEAR_IF_FIRST | TDB_DEFAULT | TDB_INCOMPATIBLE_HASH ,
2010-03-13 22:02:16 +03:00
O_RDWR | O_CREAT , 0644 ) ;
1) added void* state argument to tdb_traverse. guess what! there were
two places i found where it was appropriate to _use_ that third argument,
in locking.c and brlock.c! there was a static traverse_function and
i removed the static variable, typecast it to a void*, passed it to
tdb_traverse and re-cast it back to the traverse_function inside the
tdb_traverse function. this makes the use of tdb_traverse() reentrant,
which is never going to happen, i know, i just don't like to see
statics lying about when there's no need for them.
as i had to do in samba-tng, all uses of tdb_traverse modified to take
the new void* state argument.
2) disabled rpcclient: referring people to use SAMBA_TNG rpcclient.
i don't know how the other samba team members would react if i deleted
rpcclient from cvs main. damn, that code's so old, it's unreal.
20 rpcclient commands, instead of about 70 in SAMBA_TNG.
(This used to be commit 49d7f0afbc1c5425d53019e234d54ddf205c8e9a)
2000-02-04 07:59:31 +03:00
if ( ! tdbd ) {
2000-01-03 06:24:23 +03:00
DEBUG ( 0 , ( " Failed to open unexpected.tdb \n " ) ) ;
return ;
}
}
memset ( buf , ' \0 ' , sizeof ( buf ) ) ;
2007-10-04 00:43:55 +04:00
/* Encode the ip addr and port. */
enc_ip = ntohl ( p - > ip . s_addr ) ;
SIVAL ( buf , 0 , enc_ip ) ;
SSVAL ( buf , 4 , p - > port ) ;
len = build_packet ( & buf [ 6 ] , sizeof ( buf ) - 6 , p ) + 6 ;
2000-01-03 06:24:23 +03:00
2007-12-19 18:48:04 +03:00
ZERO_STRUCT ( key ) ; /* needed for potential alignment */
2000-01-03 06:24:23 +03:00
key . packet_type = p - > packet_type ;
key . timestamp = p - > timestamp ;
key . count = count + + ;
2007-03-29 13:35:51 +04:00
kbuf . dptr = ( uint8_t * ) & key ;
2000-01-03 06:24:23 +03:00
kbuf . dsize = sizeof ( key ) ;
2007-03-29 13:35:51 +04:00
dbuf . dptr = ( uint8_t * ) buf ;
2000-01-03 06:24:23 +03:00
dbuf . dsize = len ;
2010-03-13 22:02:16 +03:00
tdb_store ( tdbd - > tdb , kbuf , dbuf , TDB_REPLACE ) ;
2000-01-03 06:24:23 +03:00
}
static time_t lastt ;
/****************************************************************************
2007-10-04 00:43:55 +04:00
Delete the record if it is too old .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1) added void* state argument to tdb_traverse. guess what! there were
two places i found where it was appropriate to _use_ that third argument,
in locking.c and brlock.c! there was a static traverse_function and
i removed the static variable, typecast it to a void*, passed it to
tdb_traverse and re-cast it back to the traverse_function inside the
tdb_traverse function. this makes the use of tdb_traverse() reentrant,
which is never going to happen, i know, i just don't like to see
statics lying about when there's no need for them.
as i had to do in samba-tng, all uses of tdb_traverse modified to take
the new void* state argument.
2) disabled rpcclient: referring people to use SAMBA_TNG rpcclient.
i don't know how the other samba team members would react if i deleted
rpcclient from cvs main. damn, that code's so old, it's unreal.
20 rpcclient commands, instead of about 70 in SAMBA_TNG.
(This used to be commit 49d7f0afbc1c5425d53019e234d54ddf205c8e9a)
2000-02-04 07:59:31 +03:00
static int traverse_fn ( TDB_CONTEXT * ttdb , TDB_DATA kbuf , TDB_DATA dbuf , void * state )
2000-01-03 06:24:23 +03:00
{
struct unexpected_key key ;
2007-12-19 18:48:18 +03:00
if ( kbuf . dsize ! = sizeof ( key ) ) {
tdb_delete ( ttdb , kbuf ) ;
}
2000-01-03 06:24:23 +03:00
memcpy ( & key , kbuf . dptr , sizeof ( key ) ) ;
if ( lastt - key . timestamp > NMBD_UNEXPECTED_TIMEOUT ) {
tdb_delete ( ttdb , kbuf ) ;
}
return 0 ;
}
/****************************************************************************
2007-10-04 00:43:55 +04:00
Delete all old unexpected packets .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2000-01-03 06:24:23 +03:00
void clear_unexpected ( time_t t )
{
2010-11-14 07:32:36 +03:00
struct pending_unexpected * pu , * pu_next ;
for ( pu = pu_list ; pu ; pu = pu_next ) {
pu_next = pu - > next ;
if ( pu - > timeout < t ) {
DLIST_REMOVE ( pu_list , pu ) ;
2011-01-02 07:23:49 +03:00
SAFE_FREE ( pu ) ;
2010-11-14 07:32:36 +03:00
}
}
1) added void* state argument to tdb_traverse. guess what! there were
two places i found where it was appropriate to _use_ that third argument,
in locking.c and brlock.c! there was a static traverse_function and
i removed the static variable, typecast it to a void*, passed it to
tdb_traverse and re-cast it back to the traverse_function inside the
tdb_traverse function. this makes the use of tdb_traverse() reentrant,
which is never going to happen, i know, i just don't like to see
statics lying about when there's no need for them.
as i had to do in samba-tng, all uses of tdb_traverse modified to take
the new void* state argument.
2) disabled rpcclient: referring people to use SAMBA_TNG rpcclient.
i don't know how the other samba team members would react if i deleted
rpcclient from cvs main. damn, that code's so old, it's unreal.
20 rpcclient commands, instead of about 70 in SAMBA_TNG.
(This used to be commit 49d7f0afbc1c5425d53019e234d54ddf205c8e9a)
2000-02-04 07:59:31 +03:00
if ( ! tdbd ) return ;
2000-01-03 06:24:23 +03:00
if ( ( lastt ! = 0 ) & & ( t < lastt + NMBD_UNEXPECTED_TIMEOUT ) )
return ;
lastt = t ;
2010-03-13 22:02:16 +03:00
tdb_traverse ( tdbd - > tdb , traverse_fn , NULL ) ;
2000-01-03 06:24:23 +03:00
}
2007-11-24 17:47:04 +03:00
struct receive_unexpected_state {
struct packet_struct * matched_packet ;
int match_id ;
enum packet_type match_type ;
const char * match_name ;
} ;
2000-01-03 06:24:23 +03:00
/****************************************************************************
2007-10-04 00:43:55 +04:00
tdb traversal fn to find a matching 137 packet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-11-24 17:47:04 +03:00
static int traverse_match ( TDB_CONTEXT * ttdb , TDB_DATA kbuf , TDB_DATA dbuf ,
void * private_data )
2000-01-03 06:24:23 +03:00
{
2007-11-24 17:47:04 +03:00
struct receive_unexpected_state * state =
( struct receive_unexpected_state * ) private_data ;
2000-01-03 06:24:23 +03:00
struct unexpected_key key ;
2007-10-04 00:43:55 +04:00
struct in_addr ip ;
uint32_t enc_ip ;
int port ;
2000-01-03 06:24:23 +03:00
struct packet_struct * p ;
2007-12-19 18:48:18 +03:00
if ( kbuf . dsize ! = sizeof ( key ) ) {
return 0 ;
}
2000-01-03 06:24:23 +03:00
memcpy ( & key , kbuf . dptr , sizeof ( key ) ) ;
2007-11-24 17:47:04 +03:00
if ( key . packet_type ! = state - > match_type ) return 0 ;
2000-01-03 06:24:23 +03:00
2007-10-04 00:43:55 +04:00
if ( dbuf . dsize < 6 ) {
return 0 ;
}
/* Decode the ip addr and port. */
enc_ip = IVAL ( dbuf . dptr , 0 ) ;
ip . s_addr = htonl ( enc_ip ) ;
port = SVAL ( dbuf . dptr , 4 ) ;
p = parse_packet ( ( char * ) & dbuf . dptr [ 6 ] ,
dbuf . dsize - 6 ,
2007-11-24 17:47:04 +03:00
state - > match_type ,
2007-10-04 00:43:55 +04:00
ip ,
port ) ;
2009-03-25 03:05:16 +03:00
if ( ! p )
return 0 ;
2000-01-03 06:24:23 +03:00
2007-11-24 17:47:04 +03:00
if ( ( state - > match_type = = NMB_PACKET & &
p - > packet . nmb . header . name_trn_id = = state - > match_id ) | |
( state - > match_type = = DGRAM_PACKET & &
2010-11-14 07:32:36 +03:00
match_mailslot_name ( p , state - > match_name ) & &
p - > packet . dgram . header . dgm_id = = state - > match_id ) ) {
2007-11-24 17:47:04 +03:00
state - > matched_packet = p ;
2010-11-14 07:32:36 +03:00
tdb_delete ( ttdb , kbuf ) ;
2000-01-03 06:24:23 +03:00
return - 1 ;
}
free_packet ( p ) ;
return 0 ;
}
/****************************************************************************
2007-10-04 00:43:55 +04:00
Check for a particular packet in the unexpected packet queue .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct packet_struct * receive_unexpected ( enum packet_type packet_type , int id ,
2003-01-03 11:28:12 +03:00
const char * mailslot_name )
2000-01-03 06:24:23 +03:00
{
2010-03-13 22:02:16 +03:00
struct tdb_wrap * tdb2 ;
2007-11-24 17:47:04 +03:00
struct receive_unexpected_state state ;
2000-01-03 06:24:23 +03:00
2010-09-27 03:44:06 +04:00
tdb2 = tdb_wrap_open ( talloc_tos ( ) , lock_path ( " unexpected.tdb " ) , 0 , 0 ,
2010-11-14 07:32:36 +03:00
O_RDWR , 0 ) ;
2000-01-03 06:24:23 +03:00
if ( ! tdb2 ) return NULL ;
2007-11-24 17:47:04 +03:00
state . matched_packet = NULL ;
state . match_id = id ;
state . match_type = packet_type ;
state . match_name = mailslot_name ;
2000-01-03 06:24:23 +03:00
2010-03-13 22:02:16 +03:00
tdb_traverse ( tdb2 - > tdb , traverse_match , & state ) ;
2000-01-03 06:24:23 +03:00
2010-03-13 22:02:16 +03:00
TALLOC_FREE ( tdb2 ) ;
2000-01-03 06:24:23 +03:00
2007-11-24 17:47:04 +03:00
return state . matched_packet ;
2000-01-03 06:24:23 +03:00
}