1997-12-13 17:16:07 +03:00
/*
2002-01-30 09:08:46 +03:00
Unix SMB / CIFS implementation .
1997-12-13 17:16:07 +03:00
NBT netbios routines and daemon - version 2
2005-12-07 02:06:38 +03:00
Copyright ( C ) Jeremy Allison 1994 - 2005
1997-12-13 17:16:07 +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
1997-12-13 17:16:07 +03: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/>.
1997-12-13 17:16:07 +03:00
2005-12-07 02:06:38 +03:00
Converted to store WINS data in a tdb . Dec 2005. JRA .
1997-12-13 17:16:07 +03:00
*/
# include "includes.h"
2003-05-08 11:33:39 +04:00
# define WINS_LIST "wins.dat"
1998-08-30 09:43:59 +04:00
# define WINS_VERSION 1
2005-12-07 02:06:38 +03:00
# define WINSDB_VERSION 1
/****************************************************************************
We don ' t store the NetBIOS scope in the wins . tdb . We key off the ( utf8 ) netbios
name ( 65 bytes with the last byte being the name type ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
TDB_CONTEXT * wins_tdb ;
2006-06-29 04:48:44 +04:00
/****************************************************************************
Delete all the temporary name records on the in - memory linked list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void wins_delete_all_tmp_in_memory_records ( void )
{
struct name_record * nr = NULL ;
struct name_record * nrnext = NULL ;
/* Delete all temporary name records on the wins subnet linked list. */
for ( nr = wins_server_subnet - > namelist ; nr ; nr = nrnext ) {
nrnext = nr - > next ;
DLIST_REMOVE ( wins_server_subnet - > namelist , nr ) ;
SAFE_FREE ( nr - > data . ip ) ;
SAFE_FREE ( nr ) ;
}
}
2005-12-07 02:06:38 +03:00
/****************************************************************************
Convert a wins . tdb record to a struct name_record . Add in our global_scope ( ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct name_record * wins_record_to_name_record ( TDB_DATA key , TDB_DATA data )
{
struct name_record * namerec = NULL ;
uint16 nb_flags ;
unsigned char nr_src ;
uint32 death_time , refresh_time ;
uint32 id_low , id_high ;
uint32 saddr ;
uint32 wins_flags ;
uint32 num_ips ;
size_t len ;
int i ;
if ( data . dptr = = NULL | | data . dsize = = 0 ) {
return NULL ;
}
/* Min size is "wbddddddd" + 1 ip address (4). */
if ( data . dsize < 2 + 1 + ( 7 * 4 ) + 4 ) {
return NULL ;
}
len = tdb_unpack ( data . dptr , data . dsize ,
" wbddddddd " ,
& nb_flags ,
& nr_src ,
& death_time ,
& refresh_time ,
& id_low ,
& id_high ,
& saddr ,
& wins_flags ,
& num_ips ) ;
namerec = SMB_MALLOC_P ( struct name_record ) ;
if ( ! namerec ) {
return NULL ;
}
2006-06-29 00:39:07 +04:00
ZERO_STRUCTP ( namerec ) ;
2005-12-07 02:06:38 +03:00
namerec - > data . ip = SMB_MALLOC_ARRAY ( struct in_addr , num_ips ) ;
if ( ! namerec - > data . ip ) {
SAFE_FREE ( namerec ) ;
return NULL ;
}
namerec - > subnet = wins_server_subnet ;
2007-03-29 13:35:51 +04:00
push_ascii_nstring ( namerec - > name . name , ( const char * ) key . dptr ) ;
2005-12-07 02:06:38 +03:00
namerec - > name . name_type = key . dptr [ sizeof ( unstring ) ] ;
/* Add the scope. */
push_ascii ( namerec - > name . scope , global_scope ( ) , 64 , STR_TERMINATE ) ;
/* We're using a byte-by-byte compare, so we must be sure that
* unused space doesn ' t have garbage in it .
*/
for ( i = strlen ( namerec - > name . name ) ; i < sizeof ( namerec - > name . name ) ; i + + ) {
namerec - > name . name [ i ] = ' \0 ' ;
}
for ( i = strlen ( namerec - > name . scope ) ; i < sizeof ( namerec - > name . scope ) ; i + + ) {
namerec - > name . scope [ i ] = ' \0 ' ;
}
namerec - > data . nb_flags = nb_flags ;
namerec - > data . source = ( enum name_source ) nr_src ;
namerec - > data . death_time = ( time_t ) death_time ;
namerec - > data . refresh_time = ( time_t ) refresh_time ;
namerec - > data . id = id_low ;
# if defined(HAVE_LONGLONG)
namerec - > data . id | = ( ( SMB_BIG_UINT ) id_high < < 32 ) ;
# endif
namerec - > data . wins_ip . s_addr = saddr ;
namerec - > data . wins_flags = wins_flags ,
namerec - > data . num_ips = num_ips ;
for ( i = 0 ; i < num_ips ; i + + ) {
namerec - > data . ip [ i ] . s_addr = IVAL ( data . dptr , len + ( i * 4 ) ) ;
}
return namerec ;
}
/****************************************************************************
Convert a struct name_record to a wins . tdb record . Ignore the scope .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static TDB_DATA name_record_to_wins_record ( const struct name_record * namerec )
{
TDB_DATA data ;
size_t len = 0 ;
int i ;
uint32 id_low = ( namerec - > data . id & 0xFFFFFFFF ) ;
# if defined(HAVE_LONGLONG)
uint32 id_high = ( namerec - > data . id > > 32 ) & 0xFFFFFFFF ;
# else
uint32 id_high = 0 ;
# endif
ZERO_STRUCT ( data ) ;
len = ( 2 + 1 + ( 7 * 4 ) ) ; /* "wbddddddd" */
len + = ( namerec - > data . num_ips * 4 ) ;
2007-03-29 13:35:51 +04:00
data . dptr = ( uint8 * ) SMB_MALLOC ( len ) ;
2005-12-07 02:06:38 +03:00
if ( ! data . dptr ) {
return data ;
}
data . dsize = len ;
len = tdb_pack ( data . dptr , data . dsize , " wbddddddd " ,
namerec - > data . nb_flags ,
( unsigned char ) namerec - > data . source ,
( uint32 ) namerec - > data . death_time ,
( uint32 ) namerec - > data . refresh_time ,
id_low ,
id_high ,
( uint32 ) namerec - > data . wins_ip . s_addr ,
( uint32 ) namerec - > data . wins_flags ,
( uint32 ) namerec - > data . num_ips ) ;
for ( i = 0 ; i < namerec - > data . num_ips ; i + + ) {
SIVAL ( data . dptr , len + ( i * 4 ) , namerec - > data . ip [ i ] . s_addr ) ;
}
return data ;
}
/****************************************************************************
Create key . Key is UNIX codepage namestring ( usually utf8 64 byte len ) with 1 byte type .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static TDB_DATA name_to_key ( const struct nmb_name * nmbname )
{
static char keydata [ sizeof ( unstring ) + 1 ] ;
TDB_DATA key ;
memset ( keydata , ' \0 ' , sizeof ( keydata ) ) ;
pull_ascii_nstring ( keydata , sizeof ( unstring ) , nmbname - > name ) ;
strupper_m ( keydata ) ;
keydata [ sizeof ( unstring ) ] = nmbname - > name_type ;
2007-03-29 13:35:51 +04:00
key . dptr = ( uint8 * ) keydata ;
2005-12-07 02:06:38 +03:00
key . dsize = sizeof ( keydata ) ;
return key ;
}
/****************************************************************************
Lookup a given name in the wins . tdb and create a temporary malloc ' ed data struct
on the linked list . We will free this later in XXXX ( ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
struct name_record * find_name_on_wins_subnet ( const struct nmb_name * nmbname , bool self_only )
2005-12-07 02:06:38 +03:00
{
TDB_DATA data , key ;
struct name_record * nr = NULL ;
struct name_record * namerec = NULL ;
if ( ! wins_tdb ) {
return NULL ;
}
key = name_to_key ( nmbname ) ;
data = tdb_fetch ( wins_tdb , key ) ;
if ( data . dsize = = 0 ) {
return NULL ;
}
namerec = wins_record_to_name_record ( key , data ) ;
2006-02-15 21:22:00 +03:00
/* done with the this */
SAFE_FREE ( data . dptr ) ;
2005-12-07 02:06:38 +03:00
if ( ! namerec ) {
return NULL ;
}
2006-06-29 04:48:44 +04:00
/* Self names only - these include permanent names. */
if ( self_only & & ( namerec - > data . source ! = SELF_NAME ) & & ( namerec - > data . source ! = PERMANENT_NAME ) ) {
DEBUG ( 9 , ( " find_name_on_wins_subnet: self name %s NOT FOUND \n " , nmb_namestr ( nmbname ) ) ) ;
SAFE_FREE ( namerec - > data . ip ) ;
SAFE_FREE ( namerec ) ;
return NULL ;
}
2005-12-07 02:06:38 +03:00
/* Search for this name record on the list. Replace it if found. */
for ( nr = wins_server_subnet - > namelist ; nr ; nr = nr - > next ) {
if ( memcmp ( nmbname - > name , nr - > name . name , 16 ) = = 0 ) {
/* Delete it. */
DLIST_REMOVE ( wins_server_subnet - > namelist , nr ) ;
SAFE_FREE ( nr - > data . ip ) ;
SAFE_FREE ( nr ) ;
break ;
}
}
DLIST_ADD ( wins_server_subnet - > namelist , namerec ) ;
return namerec ;
}
/****************************************************************************
Overwrite or add a given name in the wins . tdb .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
static bool store_or_replace_wins_namerec ( const struct name_record * namerec , int tdb_flag )
2005-12-07 02:06:38 +03:00
{
TDB_DATA key , data ;
int ret ;
if ( ! wins_tdb ) {
return False ;
}
key = name_to_key ( & namerec - > name ) ;
data = name_record_to_wins_record ( namerec ) ;
if ( data . dptr = = NULL ) {
return False ;
}
ret = tdb_store ( wins_tdb , key , data , tdb_flag ) ;
SAFE_FREE ( data . dptr ) ;
return ( ret = = 0 ) ? True : False ;
}
/****************************************************************************
Overwrite a given name in the wins . tdb .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool wins_store_changed_namerec ( const struct name_record * namerec )
2005-12-07 02:06:38 +03:00
{
return store_or_replace_wins_namerec ( namerec , TDB_REPLACE ) ;
}
/****************************************************************************
Primary interface into creating and overwriting records in the wins . tdb .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool add_name_to_wins_subnet ( const struct name_record * namerec )
2005-12-07 02:06:38 +03:00
{
return store_or_replace_wins_namerec ( namerec , TDB_INSERT ) ;
}
/****************************************************************************
Delete a given name in the tdb and remove the temporary malloc ' ed data struct
on the linked list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool remove_name_from_wins_namelist ( struct name_record * namerec )
2005-12-07 02:06:38 +03:00
{
TDB_DATA key ;
int ret ;
if ( ! wins_tdb ) {
return False ;
}
key = name_to_key ( & namerec - > name ) ;
ret = tdb_delete ( wins_tdb , key ) ;
DLIST_REMOVE ( wins_server_subnet - > namelist , namerec ) ;
2006-01-23 17:02:17 +03:00
/* namerec must be freed by the caller */
2005-12-07 02:06:38 +03:00
return ( ret = = 0 ) ? True : False ;
}
/****************************************************************************
Dump out the complete namelist .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int traverse_fn ( TDB_CONTEXT * tdb , TDB_DATA kbuf , TDB_DATA dbuf , void * state )
{
struct name_record * namerec = NULL ;
XFILE * fp = ( XFILE * ) state ;
if ( kbuf . dsize ! = sizeof ( unstring ) + 1 ) {
return 0 ;
}
namerec = wins_record_to_name_record ( kbuf , dbuf ) ;
if ( ! namerec ) {
return 0 ;
}
dump_name_record ( namerec , fp ) ;
SAFE_FREE ( namerec - > data . ip ) ;
SAFE_FREE ( namerec ) ;
return 0 ;
}
void dump_wins_subnet_namelist ( XFILE * fp )
{
tdb_traverse ( wins_tdb , traverse_fn , ( void * ) fp ) ;
}
1997-12-13 17:16:07 +03:00
2002-01-26 01:50:15 +03:00
/****************************************************************************
2003-08-27 05:25:01 +04:00
Change the wins owner address in the record .
2002-01-26 01:50:15 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
2002-01-26 01:50:15 +03:00
static void update_wins_owner ( struct name_record * namerec , struct in_addr wins_ip )
{
namerec - > data . wins_ip = wins_ip ;
}
/****************************************************************************
2003-08-27 05:25:01 +04:00
Create the wins flags based on the nb flags and the input value .
2002-01-26 01:50:15 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
2002-01-26 01:50:15 +03:00
static void update_wins_flag ( struct name_record * namerec , int flags )
{
namerec - > data . wins_flags = 0x0 ;
/* if it's a group, it can be a normal or a special one */
if ( namerec - > data . nb_flags & NB_GROUP ) {
2005-12-07 02:06:38 +03:00
if ( namerec - > name . name_type = = 0x1C ) {
2002-01-26 01:50:15 +03:00
namerec - > data . wins_flags | = WINS_SGROUP ;
2005-12-07 02:06:38 +03:00
} else {
if ( namerec - > data . num_ips > 1 ) {
2002-01-26 01:50:15 +03:00
namerec - > data . wins_flags | = WINS_SGROUP ;
2005-12-07 02:06:38 +03:00
} else {
2002-01-26 01:50:15 +03:00
namerec - > data . wins_flags | = WINS_NGROUP ;
2005-12-07 02:06:38 +03:00
}
}
2002-01-26 01:50:15 +03:00
} else {
/* can be unique or multi-homed */
2005-12-07 02:06:38 +03:00
if ( namerec - > data . num_ips > 1 ) {
2002-01-26 01:50:15 +03:00
namerec - > data . wins_flags | = WINS_MHOMED ;
2005-12-07 02:06:38 +03:00
} else {
2002-01-26 01:50:15 +03:00
namerec - > data . wins_flags | = WINS_UNIQUE ;
2005-12-07 02:06:38 +03:00
}
2002-01-26 01:50:15 +03:00
}
/* the node type are the same bits */
namerec - > data . wins_flags | = namerec - > data . nb_flags & NB_NODETYPEMASK ;
/* the static bit is elsewhere */
2005-12-07 02:06:38 +03:00
if ( namerec - > data . death_time = = PERMANENT_TTL ) {
2002-01-26 01:50:15 +03:00
namerec - > data . wins_flags | = WINS_STATIC ;
2005-12-07 02:06:38 +03:00
}
2002-01-26 01:50:15 +03:00
/* and add the given bits */
namerec - > data . wins_flags | = flags ;
DEBUG ( 8 , ( " update_wins_flag: nbflags: 0x%x, ttl: 0x%d, flags: 0x%x, winsflags: 0x%x \n " ,
namerec - > data . nb_flags , ( int ) namerec - > data . death_time , flags , namerec - > data . wins_flags ) ) ;
}
/****************************************************************************
2003-08-27 05:25:01 +04:00
Return the general ID value and increase it if requested .
2002-01-26 01:50:15 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
2007-10-19 04:40:25 +04:00
static void get_global_id_and_update ( SMB_BIG_UINT * current_id , bool update )
2002-01-26 01:50:15 +03:00
{
/*
* it ' s kept as a static here , to prevent people from messing
* with the value directly
*/
static SMB_BIG_UINT general_id = 1 ;
DEBUG ( 5 , ( " get_global_id_and_update: updating version ID: %d \n " , ( int ) general_id ) ) ;
* current_id = general_id ;
2005-12-07 02:06:38 +03:00
if ( update ) {
2002-01-26 01:50:15 +03:00
general_id + + ;
2005-12-07 02:06:38 +03:00
}
2002-01-26 01:50:15 +03:00
}
1999-12-13 16:27:58 +03:00
/****************************************************************************
2003-08-27 05:25:01 +04:00
Possibly call the WINS hook external program when a WINS change is made .
2005-12-07 02:06:38 +03:00
Also stores the changed record back in the wins_tdb .
1999-12-13 16:27:58 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
2003-01-03 11:28:12 +03:00
static void wins_hook ( const char * operation , struct name_record * namerec , int ttl )
1999-12-13 16:27:58 +03:00
{
2007-11-20 02:15:09 +03:00
char * command = NULL ;
1999-12-13 16:27:58 +03:00
char * cmd = lp_wins_hook ( ) ;
2003-09-29 08:41:45 +04:00
char * p , * namestr ;
1999-12-13 16:27:58 +03:00
int i ;
2007-11-20 02:15:09 +03:00
TALLOC_CTX * ctx = talloc_tos ( ) ;
1999-12-13 16:27:58 +03:00
2005-12-07 02:06:38 +03:00
wins_store_changed_namerec ( namerec ) ;
if ( ! cmd | | ! * cmd ) {
return ;
}
1999-12-13 16:27:58 +03:00
for ( p = namerec - > name . name ; * p ; p + + ) {
2001-07-04 11:36:09 +04:00
if ( ! ( isalnum ( ( int ) * p ) | | strchr_m ( " ._- " , * p ) ) ) {
1999-12-13 16:27:58 +03:00
DEBUG ( 3 , ( " not calling wins hook for invalid name %s \n " , nmb_namestr ( & namerec - > name ) ) ) ;
return ;
}
}
2003-09-29 08:41:45 +04:00
/* Use the name without the nametype (and scope) appended */
namestr = nmb_namestr ( & namerec - > name ) ;
2005-12-07 02:06:38 +03:00
if ( ( p = strchr ( namestr , ' < ' ) ) ) {
2003-09-29 08:57:20 +04:00
* p = 0 ;
2005-12-07 02:06:38 +03:00
}
2003-09-29 08:41:45 +04:00
2007-11-20 02:15:09 +03:00
command = talloc_asprintf ( ctx ,
" %s %s %s %02x %d " ,
cmd ,
operation ,
namestr ,
namerec - > name . name_type ,
ttl ) ;
if ( ! command ) {
return ;
}
1999-12-13 16:27:58 +03:00
for ( i = 0 ; i < namerec - > data . num_ips ; i + + ) {
2007-11-20 02:15:09 +03:00
command = talloc_asprintf_append ( command ,
" %s " ,
inet_ntoa ( namerec - > data . ip [ i ] ) ) ;
if ( ! command ) {
return ;
}
1999-12-13 16:27:58 +03:00
}
DEBUG ( 3 , ( " calling wins hook for %s \n " , nmb_namestr ( & namerec - > name ) ) ) ;
2001-04-13 23:12:06 +04:00
smbrun ( command , NULL ) ;
2007-11-20 02:15:09 +03:00
TALLOC_FREE ( command ) ;
1999-12-13 16:27:58 +03:00
}
1997-12-13 17:16:07 +03:00
/****************************************************************************
Determine if this packet should be allocated to the WINS server .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool packet_is_for_wins_server ( struct packet_struct * packet )
1997-12-13 17:16:07 +03:00
{
2003-08-27 05:25:01 +04:00
struct nmb_packet * nmb = & packet - > packet . nmb ;
/* Only unicast packets go to a WINS server. */
if ( ( wins_server_subnet = = NULL ) | | ( nmb - > header . nm_flags . bcast = = True ) ) {
DEBUG ( 10 , ( " packet_is_for_wins_server: failing WINS test #1. \n " ) ) ;
return False ;
}
/* Check for node status requests. */
2005-12-07 02:06:38 +03:00
if ( nmb - > question . question_type ! = QUESTION_TYPE_NB_QUERY ) {
2003-08-27 05:25:01 +04:00
return False ;
2005-12-07 02:06:38 +03:00
}
2003-08-27 05:25:01 +04:00
switch ( nmb - > header . opcode ) {
/*
* A WINS server issues WACKS , not receives them .
*/
case NMB_WACK_OPCODE :
DEBUG ( 10 , ( " packet_is_for_wins_server: failing WINS test #2 (WACK). \n " ) ) ;
return False ;
/*
* A WINS server only processes registration and
* release requests , not responses .
*/
case NMB_NAME_REG_OPCODE :
case NMB_NAME_MULTIHOMED_REG_OPCODE :
case NMB_NAME_REFRESH_OPCODE_8 : /* ambiguity in rfc1002 about which is correct. */
case NMB_NAME_REFRESH_OPCODE_9 : /* WinNT uses 8 by default. */
if ( nmb - > header . response ) {
DEBUG ( 10 , ( " packet_is_for_wins_server: failing WINS test #3 (response = 1). \n " ) ) ;
return False ;
}
break ;
case NMB_NAME_RELEASE_OPCODE :
if ( nmb - > header . response ) {
DEBUG ( 10 , ( " packet_is_for_wins_server: failing WINS test #4 (response = 1). \n " ) ) ;
return False ;
}
break ;
/*
* Only process unicast name queries with rd = 1.
*/
case NMB_NAME_QUERY_OPCODE :
if ( ! nmb - > header . response & & ! nmb - > header . nm_flags . recursion_desired ) {
DEBUG ( 10 , ( " packet_is_for_wins_server: failing WINS test #5 (response = 1). \n " ) ) ;
return False ;
}
break ;
}
return True ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Utility function to decide what ttl to give a register / refresh request .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int get_ttl_from_packet ( struct nmb_packet * nmb )
{
2003-08-27 05:25:01 +04:00
int ttl = nmb - > additional - > ttl ;
1997-12-13 17:16:07 +03:00
2005-12-07 02:06:38 +03:00
if ( ttl < lp_min_wins_ttl ( ) ) {
2003-08-27 05:25:01 +04:00
ttl = lp_min_wins_ttl ( ) ;
2005-12-07 02:06:38 +03:00
}
1997-12-13 17:16:07 +03:00
2005-12-07 02:06:38 +03:00
if ( ttl > lp_max_wins_ttl ( ) ) {
2003-08-27 05:25:01 +04:00
ttl = lp_max_wins_ttl ( ) ;
2005-12-07 02:06:38 +03:00
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
return ttl ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Load or create the WINS database .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
bool initialise_wins ( void )
1997-12-13 17:16:07 +03:00
{
2003-08-27 05:25:01 +04:00
time_t time_now = time ( NULL ) ;
XFILE * fp ;
2007-11-20 02:15:09 +03:00
char line [ 1024 ] ;
2003-08-27 05:25:01 +04:00
2005-12-07 02:06:38 +03:00
if ( ! lp_we_are_a_wins_server ( ) ) {
2003-08-27 05:25:01 +04:00
return True ;
2005-12-07 02:06:38 +03:00
}
/* Open the wins.tdb. */
wins_tdb = tdb_open_log ( lock_path ( " wins.tdb " ) , 0 , TDB_DEFAULT | TDB_CLEAR_IF_FIRST , O_CREAT | O_RDWR , 0600 ) ;
if ( ! wins_tdb ) {
DEBUG ( 0 , ( " initialise_wins: failed to open wins.tdb. Error was %s \n " ,
strerror ( errno ) ) ) ;
return False ;
}
tdb_store_int32 ( wins_tdb , " WINSDB_VERSION " , WINSDB_VERSION ) ;
2003-08-27 05:25:01 +04:00
add_samba_names_to_subnet ( wins_server_subnet ) ;
2007-11-01 22:53:44 +03:00
if ( ( fp = x_fopen ( state_path ( WINS_LIST ) , O_RDONLY , 0 ) ) = = NULL ) {
2003-08-27 05:25:01 +04:00
DEBUG ( 2 , ( " initialise_wins: Can't open wins database file %s. Error was %s \n " ,
WINS_LIST , strerror ( errno ) ) ) ;
return True ;
}
while ( ! x_feof ( fp ) ) {
2007-12-08 04:32:32 +03:00
char * name_str = NULL ;
char * ip_str = NULL ;
char * ttl_str = NULL , * nb_flags_str = NULL ;
2003-08-27 05:25:01 +04:00
unsigned int num_ips ;
2007-12-08 04:32:32 +03:00
char * name = NULL ;
struct in_addr * ip_list = NULL ;
2003-08-27 05:25:01 +04:00
int type = 0 ;
int nb_flags ;
int ttl ;
const char * ptr ;
2007-12-08 04:32:32 +03:00
char * p = NULL ;
2007-10-19 04:40:25 +04:00
bool got_token ;
bool was_ip ;
2003-08-27 05:25:01 +04:00
int i ;
unsigned int hash ;
int version ;
2007-12-08 04:32:32 +03:00
TALLOC_CTX * frame = NULL ;
2003-08-27 05:25:01 +04:00
/* Read a line from the wins.dat file. Strips whitespace
from the beginning and end of the line . */
2007-12-08 04:32:32 +03:00
if ( ! fgets_slash ( line , sizeof ( line ) , fp ) ) {
2003-08-27 05:25:01 +04:00
continue ;
2007-12-08 04:32:32 +03:00
}
2007-11-20 02:15:09 +03:00
2007-12-08 04:32:32 +03:00
if ( * line = = ' # ' ) {
2003-08-27 05:25:01 +04:00
continue ;
2007-12-08 04:32:32 +03:00
}
2003-08-27 05:25:01 +04:00
if ( strncmp ( line , " VERSION " , 8 ) = = 0 ) {
if ( sscanf ( line , " VERSION %d %u " , & version , & hash ) ! = 2 | |
version ! = WINS_VERSION ) {
DEBUG ( 0 , ( " Discarding invalid wins.dat file [%s] \n " , line ) ) ;
x_fclose ( fp ) ;
return True ;
}
continue ;
}
ptr = line ;
2007-11-20 02:15:09 +03:00
/*
2003-08-27 05:25:01 +04:00
* Now we handle multiple IP addresses per name we need
* to iterate over the line twice . The first time to
* determine how many IP addresses there are , the second
* time to actually parse them into the ip_list array .
*/
2007-12-08 04:32:32 +03:00
frame = talloc_stackframe ( ) ;
if ( ! next_token_talloc ( frame , & ptr , & name_str , NULL ) ) {
2003-08-27 05:25:01 +04:00
DEBUG ( 0 , ( " initialise_wins: Failed to parse name when parsing line %s \n " , line ) ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2003-08-27 05:25:01 +04:00
continue ;
}
2007-12-08 04:32:32 +03:00
if ( ! next_token_talloc ( frame , & ptr , ttl_str , NULL ) ) {
2003-08-27 05:25:01 +04:00
DEBUG ( 0 , ( " initialise_wins: Failed to parse time to live when parsing line %s \n " , line ) ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2003-08-27 05:25:01 +04:00
continue ;
}
/*
* Determine the number of IP addresses per line .
*/
num_ips = 0 ;
do {
2007-12-08 04:32:32 +03:00
got_token = next_token_talloc ( frame , & ptr , & ip_str , NULL ) ;
2003-08-27 05:25:01 +04:00
was_ip = False ;
if ( got_token & & strchr ( ip_str , ' . ' ) ) {
num_ips + + ;
was_ip = True ;
}
2007-12-08 04:32:32 +03:00
} while ( got_token & & was_ip ) ;
2003-08-27 05:25:01 +04:00
if ( num_ips = = 0 ) {
DEBUG ( 0 , ( " initialise_wins: Missing IP address when parsing line %s \n " , line ) ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2003-08-27 05:25:01 +04:00
continue ;
}
if ( ! got_token ) {
DEBUG ( 0 , ( " initialise_wins: Missing nb_flags when parsing line %s \n " , line ) ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2003-08-27 05:25:01 +04:00
continue ;
}
/* Allocate the space for the ip_list. */
2004-12-07 21:25:53 +03:00
if ( ( ip_list = SMB_MALLOC_ARRAY ( struct in_addr , num_ips ) ) = = NULL ) {
2003-08-27 05:25:01 +04:00
DEBUG ( 0 , ( " initialise_wins: Malloc fail ! \n " ) ) ;
2006-03-06 22:27:16 +03:00
x_fclose ( fp ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2003-08-27 05:25:01 +04:00
return False ;
}
2007-11-20 02:15:09 +03:00
2003-08-27 05:25:01 +04:00
/* Reset and re-parse the line. */
ptr = line ;
2007-12-08 04:32:32 +03:00
next_token_talloc ( frame , & ptr , & name_str , NULL ) ;
next_token_talloc ( frame , & ptr , & ttl_str , NULL ) ;
2003-08-27 05:25:01 +04:00
for ( i = 0 ; i < num_ips ; i + + ) {
2007-12-08 04:32:32 +03:00
next_token_talloc ( frame , & ptr , & ip_str , NULL ) ;
2007-11-04 08:34:46 +03:00
( void ) interpret_addr2 ( & ip_list [ i ] , ip_str ) ;
2003-08-27 05:25:01 +04:00
}
2007-12-08 04:32:32 +03:00
next_token_talloc ( frame , & ptr , & nb_flags_str , NULL ) ;
2003-08-27 05:25:01 +04:00
2007-12-08 04:32:32 +03:00
/*
2003-08-27 05:25:01 +04:00
* Deal with SELF or REGISTER name encoding . Default is REGISTER
* for compatibility with old nmbds .
*/
if ( nb_flags_str [ strlen ( nb_flags_str ) - 1 ] = = ' S ' ) {
DEBUG ( 5 , ( " initialise_wins: Ignoring SELF name %s \n " , line ) ) ;
SAFE_FREE ( ip_list ) ;
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2003-08-27 05:25:01 +04:00
continue ;
}
2007-11-20 02:15:09 +03:00
2005-12-07 02:06:38 +03:00
if ( nb_flags_str [ strlen ( nb_flags_str ) - 1 ] = = ' R ' ) {
2003-08-27 05:25:01 +04:00
nb_flags_str [ strlen ( nb_flags_str ) - 1 ] = ' \0 ' ;
2005-12-07 02:06:38 +03:00
}
2007-11-20 02:15:09 +03:00
2003-08-27 05:25:01 +04:00
/* Netbios name. # divides the name from the type (hex): netbios#xx */
2007-11-20 02:15:09 +03:00
name = name_str ;
2003-08-27 05:25:01 +04:00
if ( ( p = strchr ( name , ' # ' ) ) ! = NULL ) {
* p = 0 ;
sscanf ( p + 1 , " %x " , & type ) ;
}
2007-11-20 02:15:09 +03:00
2003-08-27 05:25:01 +04:00
/* Decode the netbios flags (hex) and the time-to-live (in seconds). */
sscanf ( nb_flags_str , " %x " , & nb_flags ) ;
sscanf ( ttl_str , " %d " , & ttl ) ;
/* add all entries that have 60 seconds or more to live */
if ( ( ttl - 60 ) > time_now | | ttl = = PERMANENT_TTL ) {
2005-12-07 02:06:38 +03:00
if ( ttl ! = PERMANENT_TTL ) {
2003-08-27 05:25:01 +04:00
ttl - = time_now ;
2005-12-07 02:06:38 +03:00
}
2007-11-20 02:15:09 +03:00
2003-08-27 05:25:01 +04:00
DEBUG ( 4 , ( " initialise_wins: add name: %s#%02x ttl = %d first IP %s flags = %2x \n " ,
name , type , ttl , inet_ntoa ( ip_list [ 0 ] ) , nb_flags ) ) ;
( void ) add_name_to_subnet ( wins_server_subnet , name , type , nb_flags ,
ttl , REGISTER_NAME , num_ips , ip_list ) ;
} else {
2005-12-07 02:06:38 +03:00
DEBUG ( 4 , ( " initialise_wins: not adding name (ttl problem) "
" %s#%02x ttl = %d first IP %s flags = %2x \n " ,
2003-08-27 05:25:01 +04:00
name , type , ttl , inet_ntoa ( ip_list [ 0 ] ) , nb_flags ) ) ;
}
2003-05-08 11:33:39 +04:00
2007-12-08 04:32:32 +03:00
TALLOC_FREE ( frame ) ;
2003-08-27 05:25:01 +04:00
SAFE_FREE ( ip_list ) ;
2007-12-08 04:32:32 +03:00
}
2003-08-27 05:25:01 +04:00
x_fclose ( fp ) ;
return True ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Send a WINS WACK ( Wait ACKnowledgement ) response .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void send_wins_wack_response ( int ttl , struct packet_struct * p )
{
2003-08-27 05:25:01 +04:00
struct nmb_packet * nmb = & p - > packet . nmb ;
unsigned char rdata [ 2 ] ;
rdata [ 0 ] = rdata [ 1 ] = 0 ;
/* Taken from nmblib.c - we need to send back almost
identical bytes from the requesting packet header . */
rdata [ 0 ] = ( nmb - > header . opcode & 0xF ) < < 3 ;
2005-12-07 02:06:38 +03:00
if ( nmb - > header . nm_flags . authoritative & & nmb - > header . response ) {
2003-08-27 05:25:01 +04:00
rdata [ 0 ] | = 0x4 ;
2005-12-07 02:06:38 +03:00
}
if ( nmb - > header . nm_flags . trunc ) {
2003-08-27 05:25:01 +04:00
rdata [ 0 ] | = 0x2 ;
2005-12-07 02:06:38 +03:00
}
if ( nmb - > header . nm_flags . recursion_desired ) {
2003-08-27 05:25:01 +04:00
rdata [ 0 ] | = 0x1 ;
2005-12-07 02:06:38 +03:00
}
if ( nmb - > header . nm_flags . recursion_available & & nmb - > header . response ) {
2003-08-27 05:25:01 +04:00
rdata [ 1 ] | = 0x80 ;
2005-12-07 02:06:38 +03:00
}
if ( nmb - > header . nm_flags . bcast ) {
2003-08-27 05:25:01 +04:00
rdata [ 1 ] | = 0x10 ;
2005-12-07 02:06:38 +03:00
}
2003-08-27 05:25:01 +04:00
reply_netbios_packet ( p , /* Packet to reply to. */
0 , /* Result code. */
NMB_WAIT_ACK , /* nmbd type code. */
NMB_WACK_OPCODE , /* opcode. */
ttl , /* ttl. */
( char * ) rdata , /* data to send. */
2 ) ; /* data length. */
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Send a WINS name registration response .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void send_wins_name_registration_response ( int rcode , int ttl , struct packet_struct * p )
{
2003-08-27 05:25:01 +04:00
struct nmb_packet * nmb = & p - > packet . nmb ;
char rdata [ 6 ] ;
memcpy ( & rdata [ 0 ] , & nmb - > additional - > rdata [ 0 ] , 6 ) ;
reply_netbios_packet ( p , /* Packet to reply to. */
rcode , /* Result code. */
WINS_REG , /* nmbd type code. */
NMB_NAME_REG_OPCODE , /* opcode. */
ttl , /* ttl. */
rdata , /* data to send. */
6 ) ; /* data length. */
1997-12-13 17:16:07 +03:00
}
/***********************************************************************
Deal with a name refresh request to a WINS server .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2004-04-13 18:39:48 +04:00
void wins_process_name_refresh_request ( struct subnet_record * subrec ,
struct packet_struct * p )
1997-12-13 17:16:07 +03:00
{
2003-08-27 05:25:01 +04:00
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
2007-10-19 04:40:25 +04:00
bool bcast = nmb - > header . nm_flags . bcast ;
2003-08-27 05:25:01 +04:00
uint16 nb_flags = get_nb_flags ( nmb - > additional - > rdata ) ;
2007-10-19 04:40:25 +04:00
bool group = ( nb_flags & NB_GROUP ) ? True : False ;
2003-08-27 05:25:01 +04:00
struct name_record * namerec = NULL ;
int ttl = get_ttl_from_packet ( nmb ) ;
struct in_addr from_ip ;
2007-11-04 08:34:46 +03:00
struct in_addr our_fake_ip ;
2003-08-27 05:25:01 +04:00
2007-11-04 08:34:46 +03:00
( void ) interpret_addr2 ( & our_fake_ip , " 0.0.0.0 " ) ;
2004-04-13 18:39:48 +04:00
putip ( ( char * ) & from_ip , & nmb - > additional - > rdata [ 2 ] ) ;
2003-08-27 05:25:01 +04:00
if ( bcast ) {
/*
* We should only get unicast name refresh packets here .
2004-04-13 18:39:48 +04:00
* Anyone trying to refresh broadcast should not be going
* to a WINS server . Log an error here .
2003-08-27 05:25:01 +04:00
*/
2004-04-13 18:39:48 +04:00
if ( DEBUGLVL ( 0 ) ) {
dbgtext ( " wins_process_name_refresh_request: " ) ;
dbgtext ( " Broadcast name refresh request received " ) ;
dbgtext ( " for name %s " , nmb_namestr ( question ) ) ;
dbgtext ( " from IP %s " , inet_ntoa ( from_ip ) ) ;
dbgtext ( " on subnet %s. " , subrec - > subnet_name ) ;
dbgtext ( " Error - Broadcasts should not be sent " ) ;
dbgtext ( " to a WINS server \n " ) ;
}
2003-08-27 05:25:01 +04:00
return ;
}
1997-12-13 17:16:07 +03:00
2004-04-13 18:39:48 +04:00
if ( DEBUGLVL ( 3 ) ) {
dbgtext ( " wins_process_name_refresh_request: " ) ;
dbgtext ( " Name refresh for name %s IP %s \n " ,
nmb_namestr ( question ) , inet_ntoa ( from_ip ) ) ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/*
* See if the name already exists .
2004-04-13 18:39:48 +04:00
* If not , handle it as a name registration and return .
2003-08-27 05:25:01 +04:00
*/
namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/*
* If this is a refresh request and the name doesn ' t exist then
* treat it like a registration request . This allows us to recover
* from errors ( tridge )
*/
if ( namerec = = NULL ) {
2004-04-13 18:39:48 +04:00
if ( DEBUGLVL ( 3 ) ) {
dbgtext ( " wins_process_name_refresh_request: " ) ;
dbgtext ( " Name refresh for name %s " ,
nmb_namestr ( question ) ) ;
dbgtext ( " and the name does not exist. Treating " ) ;
dbgtext ( " as registration. \n " ) ;
}
2003-08-27 05:25:01 +04:00
wins_process_name_registration_request ( subrec , p ) ;
return ;
}
/*
2004-04-13 18:39:48 +04:00
* if the name is present but not active , simply remove it
* and treat the refresh request as a registration & return .
2003-08-27 05:25:01 +04:00
*/
if ( namerec ! = NULL & & ! WINS_STATE_ACTIVE ( namerec ) ) {
2004-04-13 18:39:48 +04:00
if ( DEBUGLVL ( 5 ) ) {
dbgtext ( " wins_process_name_refresh_request: " ) ;
dbgtext ( " Name (%s) in WINS " , nmb_namestr ( question ) ) ;
dbgtext ( " was not active - removing it. \n " ) ;
}
2003-08-27 05:25:01 +04:00
remove_name_from_namelist ( subrec , namerec ) ;
namerec = NULL ;
2004-04-13 18:39:48 +04:00
wins_process_name_registration_request ( subrec , p ) ;
2003-08-27 05:25:01 +04:00
return ;
}
/*
* Check that the group bits for the refreshing name and the
2004-04-13 18:39:48 +04:00
* name in our database match . If not , refuse the refresh .
* [ crh : Why RFS_ERR instead of ACT_ERR ? Is this what MS does ? ]
2003-08-27 05:25:01 +04:00
*/
2004-04-13 18:39:48 +04:00
if ( ( namerec ! = NULL ) & &
( ( group & & ! NAME_GROUP ( namerec ) )
| | ( ! group & & NAME_GROUP ( namerec ) ) ) ) {
if ( DEBUGLVL ( 3 ) ) {
dbgtext ( " wins_process_name_refresh_request: " ) ;
dbgtext ( " Name %s " , nmb_namestr ( question ) ) ;
dbgtext ( " group bit = %s does not match " ,
group ? " True " : " False " ) ;
dbgtext ( " group bit in WINS for this name. \n " ) ;
}
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( RFS_ERR , 0 , p ) ;
return ;
}
/*
2004-04-13 18:39:48 +04:00
* For a unique name check that the person refreshing the name is
* one of the registered IP addresses . If not - fail the refresh .
* Do the same for group names with a type of 0x1c .
* Just return success for unique 0x1d refreshes . For normal group
* names update the ttl and return success .
2003-08-27 05:25:01 +04:00
*/
2004-04-13 18:39:48 +04:00
if ( ( ! group | | ( group & & ( question - > name_type = = 0x1c ) ) )
2005-12-07 02:06:38 +03:00
& & find_ip_in_name_record ( namerec , from_ip ) ) {
2003-08-27 05:25:01 +04:00
/*
* Update the ttl .
*/
update_name_ttl ( namerec , ttl ) ;
/*
* if the record is a replica :
* we take ownership and update the version ID .
*/
2007-10-25 01:16:54 +04:00
if ( ! ip_equal_v4 ( namerec - > data . wins_ip , our_fake_ip ) ) {
2003-08-27 05:25:01 +04:00
update_wins_owner ( namerec , our_fake_ip ) ;
get_global_id_and_update ( & namerec - > data . id , True ) ;
}
send_wins_name_registration_response ( 0 , ttl , p ) ;
wins_hook ( " refresh " , namerec , ttl ) ;
return ;
2004-04-13 18:39:48 +04:00
} else if ( ( group & & ( question - > name_type = = 0x1c ) ) ) {
/*
* Added by crh for bug # 1079.
* Fix from Bert Driehuis
*/
if ( DEBUGLVL ( 3 ) ) {
dbgtext ( " wins_process_name_refresh_request: " ) ;
dbgtext ( " Name refresh for name %s, " ,
nmb_namestr ( question ) ) ;
dbgtext ( " but IP address %s " , inet_ntoa ( from_ip ) ) ;
dbgtext ( " is not yet associated with " ) ;
dbgtext ( " that name. Treating as registration. \n " ) ;
}
wins_process_name_registration_request ( subrec , p ) ;
return ;
2003-08-27 05:25:01 +04:00
} else if ( group ) {
/*
2004-04-13 18:39:48 +04:00
* Normal groups are all registered with an IP address of
* 255.255 .255 .255 so we can ' t search for the IP address .
2003-08-27 05:25:01 +04:00
*/
update_name_ttl ( namerec , ttl ) ;
2005-12-07 02:06:38 +03:00
wins_hook ( " refresh " , namerec , ttl ) ;
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( 0 , ttl , p ) ;
return ;
} else if ( ! group & & ( question - > name_type = = 0x1d ) ) {
/*
* Special name type - just pretend the refresh succeeded .
*/
send_wins_name_registration_response ( 0 , ttl , p ) ;
return ;
} else {
/*
* Fail the refresh .
*/
2004-04-13 18:39:48 +04:00
if ( DEBUGLVL ( 3 ) ) {
dbgtext ( " wins_process_name_refresh_request: " ) ;
dbgtext ( " Name refresh for name %s with IP %s " ,
nmb_namestr ( question ) , inet_ntoa ( from_ip ) ) ;
dbgtext ( " and is IP is not known to the name. \n " ) ;
}
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( RFS_ERR , 0 , p ) ;
return ;
}
1997-12-13 17:16:07 +03:00
}
/***********************************************************************
Deal with a name registration request query success to a client that
owned the name .
We have a locked pointer to the original packet stashed away in the
userdata pointer . The success here is actually a failure as it means
the client we queried wants to keep the name , so we must return
a registration failure to the original requestor .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void wins_register_query_success ( struct subnet_record * subrec ,
struct userdata_struct * userdata ,
struct nmb_name * question_name ,
struct in_addr ip ,
struct res_rec * answers )
{
2003-08-27 05:25:01 +04:00
struct packet_struct * orig_reg_packet ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
memcpy ( ( char * ) & orig_reg_packet , userdata - > data , sizeof ( struct packet_struct * ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " wins_register_query_success: Original client at IP %s still wants the \
1998-11-14 04:04:13 +03:00
name % s . Rejecting registration request . \ n " , inet_ntoa(ip), nmb_namestr(question_name) ));
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( RFS_ERR , 0 , orig_reg_packet ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
orig_reg_packet - > locked = False ;
free_packet ( orig_reg_packet ) ;
1997-12-13 17:16:07 +03:00
}
/***********************************************************************
Deal with a name registration request query failure to a client that
owned the name .
We have a locked pointer to the original packet stashed away in the
userdata pointer . The failure here is actually a success as it means
the client we queried didn ' t want to keep the name , so we can remove
the old name record and then successfully add the new name .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void wins_register_query_fail ( struct subnet_record * subrec ,
struct response_record * rrec ,
struct nmb_name * question_name ,
int rcode )
{
2003-08-27 05:25:01 +04:00
struct userdata_struct * userdata = rrec - > userdata ;
struct packet_struct * orig_reg_packet ;
struct name_record * namerec = NULL ;
memcpy ( ( char * ) & orig_reg_packet , userdata - > data , sizeof ( struct packet_struct * ) ) ;
/*
* We want to just add the name , as we now know the original owner
* didn ' t want it . But we can ' t just do that as an arbitary
* amount of time may have taken place between the name query
* request and this timeout / error response . So we check that
* the name still exists and is in the same state - if so
* we remove it and call wins_process_name_registration_request ( )
* as we know it will do the right thing now .
*/
namerec = find_name_on_subnet ( subrec , question_name , FIND_ANY_NAME ) ;
2005-12-07 02:06:38 +03:00
if ( ( namerec ! = NULL ) & & ( namerec - > data . source = = REGISTER_NAME ) & &
2007-10-25 01:16:54 +04:00
ip_equal_v4 ( rrec - > packet - > ip , * namerec - > data . ip ) ) {
2003-08-27 05:25:01 +04:00
remove_name_from_namelist ( subrec , namerec ) ;
namerec = NULL ;
}
2005-12-07 02:06:38 +03:00
if ( namerec = = NULL ) {
2003-08-27 05:25:01 +04:00
wins_process_name_registration_request ( subrec , orig_reg_packet ) ;
2005-12-07 02:06:38 +03:00
} else {
DEBUG ( 2 , ( " wins_register_query_fail: The state of the WINS database changed between "
" querying for name %s in order to replace it and this reply. \n " ,
nmb_namestr ( question_name ) ) ) ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
orig_reg_packet - > locked = False ;
free_packet ( orig_reg_packet ) ;
1997-12-13 17:16:07 +03:00
}
/***********************************************************************
Deal with a name registration request to a WINS server .
Use the following pseudocode :
registering_group
|
|
+ - - - - - - - - name exists
| |
| |
| + - - - existing name is group
| | |
| | |
| | + - - - add name ( return ) .
| |
| |
| + - - - exiting name is unique
| |
| |
| + - - - query existing owner ( return ) .
|
|
+ - - - - - - - - name doesn ' t exist
|
|
+ - - - add name ( return ) .
registering_unique
|
|
+ - - - - - - - - name exists
| |
| |
| + - - - existing name is group
| | |
| | |
| | + - - - fail add ( return ) .
| |
| |
| + - - - exiting name is unique
| |
| |
| + - - - query existing owner ( return ) .
|
|
+ - - - - - - - - name doesn ' t exist
|
|
+ - - - add name ( return ) .
As can be seen from the above , the two cases may be collapsed onto each
other with the exception of the case where the name already exists and
is a group name . This case we handle with an if statement .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void wins_process_name_registration_request ( struct subnet_record * subrec ,
struct packet_struct * p )
{
2004-03-16 00:45:45 +03:00
unstring name ;
2003-08-27 05:25:01 +04:00
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
2007-10-19 04:40:25 +04:00
bool bcast = nmb - > header . nm_flags . bcast ;
2003-08-27 05:25:01 +04:00
uint16 nb_flags = get_nb_flags ( nmb - > additional - > rdata ) ;
int ttl = get_ttl_from_packet ( nmb ) ;
struct name_record * namerec = NULL ;
struct in_addr from_ip ;
2007-10-19 04:40:25 +04:00
bool registering_group_name = ( nb_flags & NB_GROUP ) ? True : False ;
2007-11-04 08:34:46 +03:00
struct in_addr our_fake_ip ;
2003-08-27 05:25:01 +04:00
2007-11-04 08:34:46 +03:00
( void ) interpret_addr2 ( & our_fake_ip , " 0.0.0.0 " ) ;
2003-08-27 05:25:01 +04:00
putip ( ( char * ) & from_ip , & nmb - > additional - > rdata [ 2 ] ) ;
if ( bcast ) {
/*
* We should only get unicast name registration packets here .
* Anyone trying to register broadcast should not be going to a WINS
* server . Log an error here .
*/
DEBUG ( 0 , ( " wins_process_name_registration_request: broadcast name registration request \
1997-12-13 17:16:07 +03:00
received for name % s from IP % s on subnet % s . Error - should not be sent to WINS server \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) , subrec - > subnet_name ) ) ;
return ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " wins_process_name_registration_request: %s name registration for name %s \
1998-11-14 04:04:13 +03:00
IP % s \ n " , registering_group_name ? " Group " : " Unique " , nmb_namestr(question), inet_ntoa(from_ip) ));
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/*
* See if the name already exists .
*/
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/*
* if the record exists but NOT in active state ,
* consider it dead .
*/
if ( ( namerec ! = NULL ) & & ! WINS_STATE_ACTIVE ( namerec ) ) {
DEBUG ( 5 , ( " wins_process_name_registration_request: Name (%s) in WINS was \
2002-01-26 01:50:15 +03:00
not active - removing it . \ n " , nmb_namestr(question) ));
2003-08-27 05:25:01 +04:00
remove_name_from_namelist ( subrec , namerec ) ;
namerec = NULL ;
}
/*
* Deal with the case where the name found was a dns entry .
* Remove it as we now have a NetBIOS client registering the
* name .
*/
if ( ( namerec ! = NULL ) & & ( ( namerec - > data . source = = DNS_NAME ) | | ( namerec - > data . source = = DNSFAIL_NAME ) ) ) {
DEBUG ( 5 , ( " wins_process_name_registration_request: Name (%s) in WINS was \
1998-11-14 04:04:13 +03:00
a dns lookup - removing it . \ n " , nmb_namestr(question) ));
2003-08-27 05:25:01 +04:00
remove_name_from_namelist ( subrec , namerec ) ;
namerec = NULL ;
}
/*
* Reject if the name exists and is not a REGISTER_NAME .
* ( ie . Don ' t allow any static names to be overwritten .
*/
if ( ( namerec ! = NULL ) & & ( namerec - > data . source ! = REGISTER_NAME ) ) {
DEBUG ( 3 , ( " wins_process_name_registration_request: Attempt \
1998-06-09 05:56:18 +04:00
to register name % s . Name already exists in WINS with source type % d . \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( question ) , namerec - > data . source ) ) ;
send_wins_name_registration_response ( RFS_ERR , 0 , p ) ;
return ;
}
/*
* Special policy decisions based on MS documentation .
* 1 ) . All group names ( except names ending in 0x1c ) are added as 255.255 .255 .255 .
* 2 ) . All unique names ending in 0x1d are ignored , although a positive response is sent .
*/
/*
* A group name is always added as the local broadcast address , except
* for group names ending in 0x1c .
* Group names with type 0x1c are registered with individual IP addresses .
*/
2005-12-07 02:06:38 +03:00
if ( registering_group_name & & ( question - > name_type ! = 0x1c ) ) {
2007-11-04 08:34:46 +03:00
( void ) interpret_addr2 ( & from_ip , " 255.255.255.255 " ) ;
2005-12-07 02:06:38 +03:00
}
2003-08-27 05:25:01 +04:00
/*
* Ignore all attempts to register a unique 0x1d name , although return success .
*/
if ( ! registering_group_name & & ( question - > name_type = = 0x1d ) ) {
DEBUG ( 3 , ( " wins_process_name_registration_request: Ignoring request \
1999-12-13 16:27:58 +03:00
to register name % s from IP % s . \ n " , nmb_namestr(question), inet_ntoa(p->ip) ));
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( 0 , ttl , p ) ;
return ;
}
2002-01-26 01:50:15 +03:00
/*
2003-08-27 05:25:01 +04:00
* Next two cases are the ' if statement ' mentioned above .
2002-01-26 01:50:15 +03:00
*/
2003-08-27 05:25:01 +04:00
if ( ( namerec ! = NULL ) & & NAME_GROUP ( namerec ) ) {
if ( registering_group_name ) {
/*
* If we are adding a group name , the name exists and is also a group entry just add this
* IP address to it and update the ttl .
*/
DEBUG ( 3 , ( " wins_process_name_registration_request: Adding IP %s to group name %s. \n " ,
inet_ntoa ( from_ip ) , nmb_namestr ( question ) ) ) ;
/*
* Check the ip address is not already in the group .
*/
if ( ! find_ip_in_name_record ( namerec , from_ip ) ) {
add_ip_to_name_record ( namerec , from_ip ) ;
/* we need to update the record for replication */
get_global_id_and_update ( & namerec - > data . id , True ) ;
/*
* if the record is a replica , we must change
* the wins owner to us to make the replication updates
* it on the other wins servers .
* And when the partner will receive this record ,
* it will update its own record .
*/
update_wins_owner ( namerec , our_fake_ip ) ;
}
update_name_ttl ( namerec , ttl ) ;
2005-12-07 02:06:38 +03:00
wins_hook ( " refresh " , namerec , ttl ) ;
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( 0 , ttl , p ) ;
return ;
} else {
2002-01-26 01:50:15 +03:00
2003-08-27 05:25:01 +04:00
/*
* If we are adding a unique name , the name exists in the WINS db
* and is a group name then reject the registration .
*
* explanation : groups have a higher priority than unique names .
*/
DEBUG ( 3 , ( " wins_process_name_registration_request: Attempt to register name %s. Name \
1998-11-14 04:04:13 +03:00
already exists in WINS as a GROUP name . \ n " , nmb_namestr(question) ));
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( RFS_ERR , 0 , p ) ;
return ;
}
}
/*
* From here on down we know that if the name exists in the WINS db it is
* a unique name , not a group name .
*/
/*
* If the name exists and is one of our names then check the
* registering IP address . If it ' s not one of ours then automatically
* reject without doing the query - we know we will reject it .
*/
2005-12-07 02:06:38 +03:00
if ( namerec ! = NULL ) {
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( name , sizeof ( name ) , namerec - > name . name ) ;
2006-03-06 20:01:51 +03:00
if ( is_myname ( name ) ) {
2007-10-11 05:25:16 +04:00
if ( ! ismyip_v4 ( from_ip ) ) {
2006-03-06 20:01:51 +03:00
DEBUG ( 3 , ( " wins_process_name_registration_request: Attempt to register name %s. Name \
1998-11-14 04:04:13 +03:00
is one of our ( WINS server ) names . Denying registration . \ n " , nmb_namestr(question) )) ;
2006-03-06 20:01:51 +03:00
send_wins_name_registration_response ( RFS_ERR , 0 , p ) ;
return ;
} else {
/*
* It ' s one of our names and one of our IP ' s - update the ttl .
*/
update_name_ttl ( namerec , ttl ) ;
wins_hook ( " refresh " , namerec , ttl ) ;
send_wins_name_registration_response ( 0 , ttl , p ) ;
return ;
}
2003-08-27 05:25:01 +04:00
}
2006-03-06 20:01:51 +03:00
} else {
name [ 0 ] = ' \0 ' ;
2003-08-27 05:25:01 +04:00
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/*
* If the name exists and it is a unique registration and the registering IP
* is the same as the ( single ) already registered IP then just update the ttl .
*
* But not if the record is an active replica . IF it ' s a replica , it means it can be
* the same client which has moved and not yet expired . So we don ' t update
* the ttl in this case and go beyond to do a WACK and query the old client
*/
if ( ! registering_group_name
& & ( namerec ! = NULL )
& & ( namerec - > data . num_ips = = 1 )
2007-10-25 01:16:54 +04:00
& & ip_equal_v4 ( namerec - > data . ip [ 0 ] , from_ip )
& & ip_equal_v4 ( namerec - > data . wins_ip , our_fake_ip ) ) {
2003-08-27 05:25:01 +04:00
update_name_ttl ( namerec , ttl ) ;
wins_hook ( " refresh " , namerec , ttl ) ;
2005-12-07 02:06:38 +03:00
send_wins_name_registration_response ( 0 , ttl , p ) ;
2003-08-27 05:25:01 +04:00
return ;
}
/*
* Finally if the name exists do a query to the registering machine
* to see if they still claim to have the name .
*/
if ( namerec ! = NULL ) {
long * ud [ ( sizeof ( struct userdata_struct ) + sizeof ( struct packet_struct * ) ) / sizeof ( long * ) + 1 ] ;
struct userdata_struct * userdata = ( struct userdata_struct * ) ud ;
/*
* First send a WACK to the registering machine .
*/
send_wins_wack_response ( 60 , p ) ;
/*
* When the reply comes back we need the original packet .
* Lock this so it won ' t be freed and then put it into
* the userdata structure .
*/
p - > locked = True ;
userdata = ( struct userdata_struct * ) ud ;
userdata - > copy_fn = NULL ;
userdata - > free_fn = NULL ;
userdata - > userdata_len = sizeof ( struct packet_struct * ) ;
memcpy ( userdata - > data , ( char * ) & p , sizeof ( struct packet_struct * ) ) ;
/*
* Use the new call to send a query directly to an IP address .
* This sends the query directly to the IP address , and ensures
* the recursion desired flag is not set ( you were right Luke : - ) .
* This function should * only * be called from the WINS server
* code . JRA .
*/
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( name , sizeof ( name ) , question - > name ) ;
2003-08-27 05:25:01 +04:00
query_name_from_wins_server ( * namerec - > data . ip ,
name ,
question - > name_type ,
wins_register_query_success ,
wins_register_query_fail ,
userdata ) ;
return ;
}
/*
* Name did not exist - add it .
*/
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( name , sizeof ( name ) , question - > name ) ;
2003-08-27 05:25:01 +04:00
add_name_to_subnet ( subrec , name , question - > name_type ,
nb_flags , ttl , REGISTER_NAME , 1 , & from_ip ) ;
if ( ( namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ) ) {
get_global_id_and_update ( & namerec - > data . id , True ) ;
update_wins_owner ( namerec , our_fake_ip ) ;
update_wins_flag ( namerec , WINS_ACTIVE ) ;
wins_hook ( " add " , namerec , ttl ) ;
}
send_wins_name_registration_response ( 0 , ttl , p ) ;
1997-12-13 17:16:07 +03:00
}
/***********************************************************************
Deal with a mutihomed name query success to the machine that
requested the multihomed name registration .
We have a locked pointer to the original packet stashed away in the
userdata pointer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void wins_multihomed_register_query_success ( struct subnet_record * subrec ,
struct userdata_struct * userdata ,
struct nmb_name * question_name ,
struct in_addr ip ,
struct res_rec * answers )
{
2003-08-27 05:25:01 +04:00
struct packet_struct * orig_reg_packet ;
struct nmb_packet * nmb ;
struct name_record * namerec = NULL ;
struct in_addr from_ip ;
int ttl ;
2007-11-04 08:34:46 +03:00
struct in_addr our_fake_ip ;
2003-08-27 05:25:01 +04:00
2007-11-04 08:34:46 +03:00
( void ) interpret_addr2 ( & our_fake_ip , " 0.0.0.0 " ) ;
2003-08-27 05:25:01 +04:00
memcpy ( ( char * ) & orig_reg_packet , userdata - > data , sizeof ( struct packet_struct * ) ) ;
nmb = & orig_reg_packet - > packet . nmb ;
putip ( ( char * ) & from_ip , & nmb - > additional - > rdata [ 2 ] ) ;
ttl = get_ttl_from_packet ( nmb ) ;
/*
* We want to just add the new IP , as we now know the requesting
* machine claims to own it . But we can ' t just do that as an arbitary
* amount of time may have taken place between the name query
* request and this response . So we check that
* the name still exists and is in the same state - if so
* we just add the extra IP and update the ttl .
*/
namerec = find_name_on_subnet ( subrec , question_name , FIND_ANY_NAME ) ;
if ( ( namerec = = NULL ) | | ( namerec - > data . source ! = REGISTER_NAME ) | | ! WINS_STATE_ACTIVE ( namerec ) ) {
DEBUG ( 3 , ( " wins_multihomed_register_query_success: name %s is not in the correct state to add \
2002-07-15 14:35:28 +04:00
a subsequent IP address . \ n " , nmb_namestr(question_name) ));
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( RFS_ERR , 0 , orig_reg_packet ) ;
1998-06-26 03:51:28 +04:00
2003-08-27 05:25:01 +04:00
orig_reg_packet - > locked = False ;
free_packet ( orig_reg_packet ) ;
1998-06-26 03:51:28 +04:00
2003-08-27 05:25:01 +04:00
return ;
}
1997-12-13 17:16:07 +03:00
2005-12-07 02:06:38 +03:00
if ( ! find_ip_in_name_record ( namerec , from_ip ) ) {
2003-08-27 05:25:01 +04:00
add_ip_to_name_record ( namerec , from_ip ) ;
2005-12-07 02:06:38 +03:00
}
2002-01-26 01:50:15 +03:00
2003-08-27 05:25:01 +04:00
get_global_id_and_update ( & namerec - > data . id , True ) ;
update_wins_owner ( namerec , our_fake_ip ) ;
update_wins_flag ( namerec , WINS_ACTIVE ) ;
update_name_ttl ( namerec , ttl ) ;
wins_hook ( " add " , namerec , ttl ) ;
2005-12-07 02:06:38 +03:00
send_wins_name_registration_response ( 0 , ttl , orig_reg_packet ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
orig_reg_packet - > locked = False ;
free_packet ( orig_reg_packet ) ;
1997-12-13 17:16:07 +03:00
}
/***********************************************************************
Deal with a name registration request query failure to a client that
owned the name .
We have a locked pointer to the original packet stashed away in the
userdata pointer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void wins_multihomed_register_query_fail ( struct subnet_record * subrec ,
struct response_record * rrec ,
struct nmb_name * question_name ,
int rcode )
{
2003-08-27 05:25:01 +04:00
struct userdata_struct * userdata = rrec - > userdata ;
struct packet_struct * orig_reg_packet ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
memcpy ( ( char * ) & orig_reg_packet , userdata - > data , sizeof ( struct packet_struct * ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " wins_multihomed_register_query_fail: Registering machine at IP %s failed to answer \
1998-11-14 04:04:13 +03:00
query successfully for name % s . \ n " , inet_ntoa(orig_reg_packet->ip), nmb_namestr(question_name) ));
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( RFS_ERR , 0 , orig_reg_packet ) ;
1998-06-26 03:51:28 +04:00
2003-08-27 05:25:01 +04:00
orig_reg_packet - > locked = False ;
free_packet ( orig_reg_packet ) ;
return ;
1997-12-13 17:16:07 +03:00
}
/***********************************************************************
Deal with a multihomed name registration request to a WINS server .
These cannot be group name registrations .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void wins_process_multihomed_name_registration_request ( struct subnet_record * subrec ,
struct packet_struct * p )
{
2003-08-27 05:25:01 +04:00
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
2007-10-19 04:40:25 +04:00
bool bcast = nmb - > header . nm_flags . bcast ;
2003-08-27 05:25:01 +04:00
uint16 nb_flags = get_nb_flags ( nmb - > additional - > rdata ) ;
int ttl = get_ttl_from_packet ( nmb ) ;
struct name_record * namerec = NULL ;
struct in_addr from_ip ;
2007-10-19 04:40:25 +04:00
bool group = ( nb_flags & NB_GROUP ) ? True : False ;
2007-11-04 08:34:46 +03:00
struct in_addr our_fake_ip ;
2004-03-16 00:45:45 +03:00
unstring qname ;
2003-08-27 05:25:01 +04:00
2007-11-04 08:34:46 +03:00
( void ) interpret_addr2 ( & our_fake_ip , " 0.0.0.0 " ) ;
2003-08-27 05:25:01 +04:00
putip ( ( char * ) & from_ip , & nmb - > additional - > rdata [ 2 ] ) ;
if ( bcast ) {
/*
* We should only get unicast name registration packets here .
* Anyone trying to register broadcast should not be going to a WINS
* server . Log an error here .
*/
DEBUG ( 0 , ( " wins_process_multihomed_name_registration_request: broadcast name registration request \
1997-12-13 17:16:07 +03:00
received for name % s from IP % s on subnet % s . Error - should not be sent to WINS server \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) , subrec - > subnet_name ) ) ;
return ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/*
* Only unique names should be registered multihomed .
*/
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
if ( group ) {
DEBUG ( 0 , ( " wins_process_multihomed_name_registration_request: group name registration request \
1997-12-13 17:16:07 +03:00
received for name % s from IP % s on subnet % s . Errror - group names should not be multihomed . \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) , subrec - > subnet_name ) ) ;
return ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " wins_process_multihomed_name_registration_request: name registration for name %s \
1998-11-14 04:04:13 +03:00
IP % s \ n " , nmb_namestr(question), inet_ntoa(from_ip) ));
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/*
* Deal with policy regarding 0x1d names .
*/
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
if ( question - > name_type = = 0x1d ) {
DEBUG ( 3 , ( " wins_process_multihomed_name_registration_request: Ignoring request \
1998-11-14 04:04:13 +03:00
to register name % s from IP % s . " , nmb_namestr(question), inet_ntoa(p->ip) ));
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( 0 , ttl , p ) ;
return ;
}
/*
* See if the name already exists .
*/
namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ;
/*
* if the record exists but NOT in active state ,
* consider it dead .
*/
if ( ( namerec ! = NULL ) & & ! WINS_STATE_ACTIVE ( namerec ) ) {
DEBUG ( 5 , ( " wins_process_multihomed_name_registration_request: Name (%s) in WINS was not active - removing it. \n " , nmb_namestr ( question ) ) ) ;
remove_name_from_namelist ( subrec , namerec ) ;
namerec = NULL ;
}
2002-07-15 14:35:28 +04:00
2003-08-27 05:25:01 +04:00
/*
* Deal with the case where the name found was a dns entry .
* Remove it as we now have a NetBIOS client registering the
* name .
*/
if ( ( namerec ! = NULL ) & & ( ( namerec - > data . source = = DNS_NAME ) | | ( namerec - > data . source = = DNSFAIL_NAME ) ) ) {
DEBUG ( 5 , ( " wins_process_multihomed_name_registration_request: Name (%s) in WINS was a dns lookup \
1998-11-14 04:04:13 +03:00
- removing it . \ n " , nmb_namestr(question) ));
2003-08-27 05:25:01 +04:00
remove_name_from_namelist ( subrec , namerec ) ;
namerec = NULL ;
}
/*
* Reject if the name exists and is not a REGISTER_NAME .
* ( ie . Don ' t allow any static names to be overwritten .
*/
if ( ( namerec ! = NULL ) & & ( namerec - > data . source ! = REGISTER_NAME ) ) {
DEBUG ( 3 , ( " wins_process_multihomed_name_registration_request: Attempt \
1998-06-09 05:56:18 +04:00
to register name % s . Name already exists in WINS with source type % d . \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( question ) , namerec - > data . source ) ) ;
send_wins_name_registration_response ( RFS_ERR , 0 , p ) ;
return ;
}
/*
* Reject if the name exists and is a GROUP name and is active .
*/
if ( ( namerec ! = NULL ) & & NAME_GROUP ( namerec ) & & WINS_STATE_ACTIVE ( namerec ) ) {
DEBUG ( 3 , ( " wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1998-11-14 04:04:13 +03:00
already exists in WINS as a GROUP name . \ n " , nmb_namestr(question) ));
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( RFS_ERR , 0 , p ) ;
return ;
}
/*
* From here on down we know that if the name exists in the WINS db it is
* a unique name , not a group name .
*/
/*
* If the name exists and is one of our names then check the
* registering IP address . If it ' s not one of ours then automatically
* reject without doing the query - we know we will reject it .
*/
if ( ( namerec ! = NULL ) & & ( is_myname ( namerec - > name . name ) ) ) {
2007-10-11 05:25:16 +04:00
if ( ! ismyip_v4 ( from_ip ) ) {
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " wins_process_multihomed_name_registration_request: Attempt to register name %s. Name \
1998-11-14 04:04:13 +03:00
is one of our ( WINS server ) names . Denying registration . \ n " , nmb_namestr(question) )) ;
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( RFS_ERR , 0 , p ) ;
return ;
} else {
/*
* It ' s one of our names and one of our IP ' s . Ensure the IP is in the record and
* update the ttl . Update the version ID to force replication .
*/
2005-12-07 02:06:38 +03:00
update_name_ttl ( namerec , ttl ) ;
2003-08-27 05:25:01 +04:00
if ( ! find_ip_in_name_record ( namerec , from_ip ) ) {
get_global_id_and_update ( & namerec - > data . id , True ) ;
update_wins_owner ( namerec , our_fake_ip ) ;
update_wins_flag ( namerec , WINS_ACTIVE ) ;
add_ip_to_name_record ( namerec , from_ip ) ;
}
2005-12-07 02:06:38 +03:00
wins_hook ( " refresh " , namerec , ttl ) ;
2003-08-27 05:25:01 +04:00
send_wins_name_registration_response ( 0 , ttl , p ) ;
return ;
}
}
/*
* If the name exists and is active , check if the IP address is already registered
* to that name . If so then update the ttl and reply success .
*/
if ( ( namerec ! = NULL ) & & find_ip_in_name_record ( namerec , from_ip ) & & WINS_STATE_ACTIVE ( namerec ) ) {
update_name_ttl ( namerec , ttl ) ;
/*
* If it ' s a replica , we need to become the wins owner
* to force the replication
*/
2007-10-25 01:16:54 +04:00
if ( ! ip_equal_v4 ( namerec - > data . wins_ip , our_fake_ip ) ) {
2003-08-27 05:25:01 +04:00
get_global_id_and_update ( & namerec - > data . id , True ) ;
update_wins_owner ( namerec , our_fake_ip ) ;
update_wins_flag ( namerec , WINS_ACTIVE ) ;
}
2002-01-26 01:50:15 +03:00
2003-08-27 05:25:01 +04:00
wins_hook ( " refresh " , namerec , ttl ) ;
2005-12-07 02:06:38 +03:00
send_wins_name_registration_response ( 0 , ttl , p ) ;
2003-08-27 05:25:01 +04:00
return ;
}
/*
* If the name exists do a query to the owner
* to see if they still want the name .
*/
if ( namerec ! = NULL ) {
long * ud [ ( sizeof ( struct userdata_struct ) + sizeof ( struct packet_struct * ) ) / sizeof ( long * ) + 1 ] ;
struct userdata_struct * userdata = ( struct userdata_struct * ) ud ;
/*
* First send a WACK to the registering machine .
*/
send_wins_wack_response ( 60 , p ) ;
/*
* When the reply comes back we need the original packet .
* Lock this so it won ' t be freed and then put it into
* the userdata structure .
*/
p - > locked = True ;
userdata = ( struct userdata_struct * ) ud ;
userdata - > copy_fn = NULL ;
userdata - > free_fn = NULL ;
userdata - > userdata_len = sizeof ( struct packet_struct * ) ;
memcpy ( userdata - > data , ( char * ) & p , sizeof ( struct packet_struct * ) ) ;
/*
* Use the new call to send a query directly to an IP address .
* This sends the query directly to the IP address , and ensures
* the recursion desired flag is not set ( you were right Luke : - ) .
* This function should * only * be called from the WINS server
* code . JRA .
*
* Note that this packet is sent to the current owner of the name ,
* not the person who sent the packet
*/
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( qname , sizeof ( qname ) , question - > name ) ;
2003-08-27 05:25:01 +04:00
query_name_from_wins_server ( namerec - > data . ip [ 0 ] ,
qname ,
question - > name_type ,
wins_multihomed_register_query_success ,
wins_multihomed_register_query_fail ,
userdata ) ;
return ;
}
/*
* Name did not exist - add it .
*/
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( qname , sizeof ( qname ) , question - > name ) ;
2003-08-27 05:25:01 +04:00
add_name_to_subnet ( subrec , qname , question - > name_type ,
nb_flags , ttl , REGISTER_NAME , 1 , & from_ip ) ;
if ( ( namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ) ) {
get_global_id_and_update ( & namerec - > data . id , True ) ;
update_wins_owner ( namerec , our_fake_ip ) ;
update_wins_flag ( namerec , WINS_ACTIVE ) ;
wins_hook ( " add " , namerec , ttl ) ;
}
send_wins_name_registration_response ( 0 , ttl , p ) ;
1997-12-13 17:16:07 +03:00
}
2005-12-07 02:06:38 +03:00
/***********************************************************************
Fetch all * < 1 b > names from the WINS db and store on the namelist .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int fetch_1b_traverse_fn ( TDB_CONTEXT * tdb , TDB_DATA kbuf , TDB_DATA dbuf , void * state )
{
struct name_record * namerec = NULL ;
if ( kbuf . dsize ! = sizeof ( unstring ) + 1 ) {
return 0 ;
}
/* Filter out all non-1b names. */
if ( kbuf . dptr [ sizeof ( unstring ) ] ! = 0x1b ) {
return 0 ;
}
namerec = wins_record_to_name_record ( kbuf , dbuf ) ;
if ( ! namerec ) {
return 0 ;
}
DLIST_ADD ( wins_server_subnet - > namelist , namerec ) ;
return 0 ;
}
void fetch_all_active_wins_1b_names ( void )
{
tdb_traverse ( wins_tdb , fetch_1b_traverse_fn , NULL ) ;
}
1997-12-13 17:16:07 +03:00
/***********************************************************************
Deal with the special name query for * < 1 b > .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void process_wins_dmb_query_request ( struct subnet_record * subrec ,
struct packet_struct * p )
{
2003-08-27 05:25:01 +04:00
struct name_record * namerec = NULL ;
char * prdata ;
int num_ips ;
/*
* Go through all the ACTIVE names in the WINS db looking for those
* ending in < 1 b > . Use this to calculate the number of IP
* addresses we need to return .
*/
num_ips = 0 ;
2005-12-07 02:06:38 +03:00
2006-06-29 04:48:44 +04:00
/* First, clear the in memory list - we're going to re-populate
it with the tdb_traversal in fetch_all_active_wins_1b_names . */
wins_delete_all_tmp_in_memory_records ( ) ;
2005-12-07 02:06:38 +03:00
fetch_all_active_wins_1b_names ( ) ;
for ( namerec = subrec - > namelist ; namerec ; namerec = namerec - > next ) {
if ( WINS_STATE_ACTIVE ( namerec ) & & namerec - > name . name_type = = 0x1b ) {
2003-08-27 05:25:01 +04:00
num_ips + = namerec - > data . num_ips ;
2005-12-07 02:06:38 +03:00
}
2003-08-27 05:25:01 +04:00
}
if ( num_ips = = 0 ) {
/*
* There are no 0x1b names registered . Return name query fail .
*/
send_wins_name_query_response ( NAM_ERR , p , NULL ) ;
return ;
}
2004-12-07 21:25:53 +03:00
if ( ( prdata = ( char * ) SMB_MALLOC ( num_ips * 6 ) ) = = NULL ) {
2003-08-27 05:25:01 +04:00
DEBUG ( 0 , ( " process_wins_dmb_query_request: Malloc fail !. \n " ) ) ;
return ;
}
/*
* Go through all the names again in the WINS db looking for those
* ending in < 1 b > . Add their IP addresses into the list we will
* return .
*/
num_ips = 0 ;
2005-12-07 02:06:38 +03:00
for ( namerec = subrec - > namelist ; namerec ; namerec = namerec - > next ) {
if ( WINS_STATE_ACTIVE ( namerec ) & & namerec - > name . name_type = = 0x1b ) {
2003-08-27 05:25:01 +04:00
int i ;
for ( i = 0 ; i < namerec - > data . num_ips ; i + + ) {
set_nb_flags ( & prdata [ num_ips * 6 ] , namerec - > data . nb_flags ) ;
putip ( ( char * ) & prdata [ ( num_ips * 6 ) + 2 ] , & namerec - > data . ip [ i ] ) ;
num_ips + + ;
}
}
}
/*
* Send back the reply containing the IP list .
*/
reply_netbios_packet ( p , /* Packet to reply to. */
0 , /* Result code. */
WINS_QUERY , /* nmbd type code. */
NMB_NAME_QUERY_OPCODE , /* opcode. */
lp_min_wins_ttl ( ) , /* ttl. */
prdata , /* data to send. */
num_ips * 6 ) ; /* data length. */
SAFE_FREE ( prdata ) ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Send a WINS name query response .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void send_wins_name_query_response ( int rcode , struct packet_struct * p ,
struct name_record * namerec )
{
2003-08-27 05:25:01 +04:00
char rdata [ 6 ] ;
char * prdata = rdata ;
int reply_data_len = 0 ;
int ttl = 0 ;
int i ;
memset ( rdata , ' \0 ' , 6 ) ;
if ( rcode = = 0 ) {
ttl = ( namerec - > data . death_time ! = PERMANENT_TTL ) ? namerec - > data . death_time - p - > timestamp : lp_max_wins_ttl ( ) ;
/* Copy all known ip addresses into the return data. */
/* Optimise for the common case of one IP address so we don't need a malloc. */
if ( namerec - > data . num_ips = = 1 ) {
prdata = rdata ;
} else {
2004-12-07 21:25:53 +03:00
if ( ( prdata = ( char * ) SMB_MALLOC ( namerec - > data . num_ips * 6 ) ) = = NULL ) {
2003-08-27 05:25:01 +04:00
DEBUG ( 0 , ( " send_wins_name_query_response: malloc fail ! \n " ) ) ;
return ;
}
}
for ( i = 0 ; i < namerec - > data . num_ips ; i + + ) {
set_nb_flags ( & prdata [ i * 6 ] , namerec - > data . nb_flags ) ;
putip ( ( char * ) & prdata [ 2 + ( i * 6 ) ] , & namerec - > data . ip [ i ] ) ;
}
sort_query_replies ( prdata , i , p - > ip ) ;
reply_data_len = namerec - > data . num_ips * 6 ;
}
reply_netbios_packet ( p , /* Packet to reply to. */
rcode , /* Result code. */
WINS_QUERY , /* nmbd type code. */
NMB_NAME_QUERY_OPCODE , /* opcode. */
ttl , /* ttl. */
prdata , /* data to send. */
reply_data_len ) ; /* data length. */
2005-12-07 02:06:38 +03:00
if ( prdata ! = rdata ) {
2003-08-27 05:25:01 +04:00
SAFE_FREE ( prdata ) ;
2005-12-07 02:06:38 +03:00
}
1997-12-13 17:16:07 +03:00
}
/***********************************************************************
Deal with a name query .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void wins_process_name_query_request ( struct subnet_record * subrec ,
struct packet_struct * p )
{
2003-08-27 05:25:01 +04:00
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
struct name_record * namerec = NULL ;
2004-03-16 00:45:45 +03:00
unstring qname ;
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " wins_process_name_query: name query for name %s from IP %s \n " ,
nmb_namestr ( question ) , inet_ntoa ( p - > ip ) ) ) ;
/*
* Special name code . If the queried name is * < 1 b > then search
* the entire WINS database and return a list of all the IP addresses
* registered to any < 1 b > name . This is to allow domain master browsers
* to discover other domains that may not have a presence on their subnet .
*/
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( qname , sizeof ( qname ) , question - > name ) ;
2003-08-27 05:25:01 +04:00
if ( strequal ( qname , " * " ) & & ( question - > name_type = = 0x1b ) ) {
process_wins_dmb_query_request ( subrec , p ) ;
return ;
}
namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ;
if ( namerec ! = NULL ) {
/*
* If the name is not anymore in active state then reply not found .
* it ' s fair even if we keep it in the cache for days .
*/
if ( ! WINS_STATE_ACTIVE ( namerec ) ) {
DEBUG ( 3 , ( " wins_process_name_query: name query for name %s - name expired. Returning fail. \n " ,
nmb_namestr ( question ) ) ) ;
send_wins_name_query_response ( NAM_ERR , p , namerec ) ;
return ;
}
/*
* If it ' s a DNSFAIL_NAME then reply name not found .
*/
if ( namerec - > data . source = = DNSFAIL_NAME ) {
DEBUG ( 3 , ( " wins_process_name_query: name query for name %s returning DNS fail. \n " ,
nmb_namestr ( question ) ) ) ;
send_wins_name_query_response ( NAM_ERR , p , namerec ) ;
return ;
}
/*
* If the name has expired then reply name not found .
*/
if ( ( namerec - > data . death_time ! = PERMANENT_TTL ) & & ( namerec - > data . death_time < p - > timestamp ) ) {
DEBUG ( 3 , ( " wins_process_name_query: name query for name %s - name expired. Returning fail. \n " ,
nmb_namestr ( question ) ) ) ;
send_wins_name_query_response ( NAM_ERR , p , namerec ) ;
return ;
}
DEBUG ( 3 , ( " wins_process_name_query: name query for name %s returning first IP %s. \n " ,
nmb_namestr ( question ) , inet_ntoa ( namerec - > data . ip [ 0 ] ) ) ) ;
send_wins_name_query_response ( 0 , p , namerec ) ;
return ;
}
/*
* Name not found in WINS - try a dns query if it ' s a 0x20 name .
*/
if ( lp_dns_proxy ( ) & & ( ( question - > name_type = = 0x20 ) | | question - > name_type = = 0 ) ) {
DEBUG ( 3 , ( " wins_process_name_query: name query for name %s not found - doing dns lookup. \n " ,
nmb_namestr ( question ) ) ) ;
2005-12-07 02:06:38 +03:00
queue_dns_query ( p , question ) ;
2003-08-27 05:25:01 +04:00
return ;
}
/*
* Name not found - return error .
*/
send_wins_name_query_response ( NAM_ERR , p , NULL ) ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Send a WINS name release response .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void send_wins_name_release_response ( int rcode , struct packet_struct * p )
{
2003-08-27 05:25:01 +04:00
struct nmb_packet * nmb = & p - > packet . nmb ;
char rdata [ 6 ] ;
memcpy ( & rdata [ 0 ] , & nmb - > additional - > rdata [ 0 ] , 6 ) ;
reply_netbios_packet ( p , /* Packet to reply to. */
rcode , /* Result code. */
NMB_REL , /* nmbd type code. */
NMB_NAME_RELEASE_OPCODE , /* opcode. */
0 , /* ttl. */
rdata , /* data to send. */
6 ) ; /* data length. */
1997-12-13 17:16:07 +03:00
}
/***********************************************************************
Deal with a name release .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void wins_process_name_release_request ( struct subnet_record * subrec ,
struct packet_struct * p )
{
2003-08-27 05:25:01 +04:00
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
2007-10-19 04:40:25 +04:00
bool bcast = nmb - > header . nm_flags . bcast ;
2003-08-27 05:25:01 +04:00
uint16 nb_flags = get_nb_flags ( nmb - > additional - > rdata ) ;
struct name_record * namerec = NULL ;
struct in_addr from_ip ;
2007-10-19 04:40:25 +04:00
bool releasing_group_name = ( nb_flags & NB_GROUP ) ? True : False ; ;
2003-08-27 05:25:01 +04:00
putip ( ( char * ) & from_ip , & nmb - > additional - > rdata [ 2 ] ) ;
if ( bcast ) {
/*
* We should only get unicast name registration packets here .
* Anyone trying to register broadcast should not be going to a WINS
* server . Log an error here .
*/
DEBUG ( 0 , ( " wins_process_name_release_request: broadcast name registration request \
1997-12-13 17:16:07 +03:00
received for name % s from IP % s on subnet % s . Error - should not be sent to WINS server \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) , subrec - > subnet_name ) ) ;
return ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " wins_process_name_release_request: %s name release for name %s \
1998-11-14 04:04:13 +03:00
IP % s \ n " , releasing_group_name ? " Group " : " Unique " , nmb_namestr(question), inet_ntoa(from_ip) ));
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/*
* Deal with policy regarding 0x1d names .
*/
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
if ( ! releasing_group_name & & ( question - > name_type = = 0x1d ) ) {
DEBUG ( 3 , ( " wins_process_name_release_request: Ignoring request \
1998-11-14 04:04:13 +03:00
to release name % s from IP % s . " , nmb_namestr(question), inet_ntoa(p->ip) ));
2003-08-27 05:25:01 +04:00
send_wins_name_release_response ( 0 , p ) ;
return ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/*
* See if the name already exists .
*/
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ;
if ( ( namerec = = NULL ) | | ( ( namerec ! = NULL ) & & ( namerec - > data . source ! = REGISTER_NAME ) ) ) {
send_wins_name_release_response ( NAM_ERR , p ) ;
return ;
}
/*
* Check that the sending machine has permission to release this name .
* If it ' s a group name not ending in 0x1c then just say yes and let
* the group time out .
*/
if ( releasing_group_name & & ( question - > name_type ! = 0x1c ) ) {
send_wins_name_release_response ( 0 , p ) ;
return ;
}
/*
* Check that the releasing node is on the list of IP addresses
* for this name . Disallow the release if not .
*/
if ( ! find_ip_in_name_record ( namerec , from_ip ) ) {
DEBUG ( 3 , ( " wins_process_name_release_request: Refusing request to \
1997-12-13 17:16:07 +03:00
release name % s as IP % s is not one of the known IP ' s for this name . \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) ) ) ;
send_wins_name_release_response ( NAM_ERR , p ) ;
return ;
}
/*
* Check if the record is active . IF it ' s already released
* or tombstoned , refuse the release .
*/
if ( ! WINS_STATE_ACTIVE ( namerec ) ) {
DEBUG ( 3 , ( " wins_process_name_release_request: Refusing request to \
release name % s as this record is not active anymore . \ n " , nmb_namestr(question) ));
send_wins_name_release_response ( NAM_ERR , p ) ;
return ;
}
/*
* Check if the record is a 0x1c group
* and has more then one ip
* remove only this address .
*/
if ( releasing_group_name & & ( question - > name_type = = 0x1c ) & & ( namerec - > data . num_ips > 1 ) ) {
remove_ip_from_name_record ( namerec , from_ip ) ;
DEBUG ( 3 , ( " wins_process_name_release_request: Remove IP %s from NAME: %s \n " ,
inet_ntoa ( from_ip ) , nmb_namestr ( question ) ) ) ;
2005-12-07 02:06:38 +03:00
wins_hook ( " delete " , namerec , 0 ) ;
2003-08-27 05:25:01 +04:00
send_wins_name_release_response ( 0 , p ) ;
return ;
}
2002-11-15 21:55:18 +03:00
2003-08-27 05:25:01 +04:00
/*
* Send a release response .
* Flag the name as released and update the ttl
*/
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
namerec - > data . wins_flags | = WINS_RELEASED ;
update_name_ttl ( namerec , EXTINCTION_INTERVAL ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
wins_hook ( " delete " , namerec , 0 ) ;
2005-12-07 02:06:38 +03:00
send_wins_name_release_response ( 0 , p ) ;
1997-12-13 17:16:07 +03:00
}
/*******************************************************************
WINS time dependent processing .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-12-07 02:06:38 +03:00
static int wins_processing_traverse_fn ( TDB_CONTEXT * tdb , TDB_DATA kbuf , TDB_DATA dbuf , void * state )
{
time_t t = * ( time_t * ) state ;
2007-10-19 04:40:25 +04:00
bool store_record = False ;
2005-12-07 02:06:38 +03:00
struct name_record * namerec = NULL ;
2007-11-04 08:34:46 +03:00
struct in_addr our_fake_ip ;
2005-12-07 02:06:38 +03:00
2007-11-04 08:34:46 +03:00
( void ) interpret_addr2 ( & our_fake_ip , " 0.0.0.0 " ) ;
2005-12-07 02:06:38 +03:00
if ( kbuf . dsize ! = sizeof ( unstring ) + 1 ) {
return 0 ;
}
namerec = wins_record_to_name_record ( kbuf , dbuf ) ;
if ( ! namerec ) {
return 0 ;
}
if ( ( namerec - > data . death_time ! = PERMANENT_TTL ) & & ( namerec - > data . death_time < t ) ) {
if ( namerec - > data . source = = SELF_NAME ) {
DEBUG ( 3 , ( " wins_processing_traverse_fn: Subnet %s not expiring SELF name %s \n " ,
wins_server_subnet - > subnet_name , nmb_namestr ( & namerec - > name ) ) ) ;
namerec - > data . death_time + = 300 ;
store_record = True ;
goto done ;
} else if ( namerec - > data . source = = DNS_NAME | | namerec - > data . source = = DNSFAIL_NAME ) {
DEBUG ( 3 , ( " wins_processing_traverse_fn: deleting timed out DNS name %s \n " ,
nmb_namestr ( & namerec - > name ) ) ) ;
remove_name_from_wins_namelist ( namerec ) ;
goto done ;
}
/* handle records, samba is the wins owner */
2007-10-25 01:16:54 +04:00
if ( ip_equal_v4 ( namerec - > data . wins_ip , our_fake_ip ) ) {
2007-06-12 05:45:40 +04:00
switch ( namerec - > data . wins_flags & WINS_STATE_MASK ) {
2005-12-07 02:06:38 +03:00
case WINS_ACTIVE :
namerec - > data . wins_flags & = ~ WINS_STATE_MASK ;
namerec - > data . wins_flags | = WINS_RELEASED ;
namerec - > data . death_time = t + EXTINCTION_INTERVAL ;
DEBUG ( 3 , ( " wins_processing_traverse_fn: expiring %s \n " ,
nmb_namestr ( & namerec - > name ) ) ) ;
store_record = True ;
goto done ;
case WINS_RELEASED :
namerec - > data . wins_flags & = ~ WINS_STATE_MASK ;
namerec - > data . wins_flags | = WINS_TOMBSTONED ;
namerec - > data . death_time = t + EXTINCTION_TIMEOUT ;
get_global_id_and_update ( & namerec - > data . id , True ) ;
DEBUG ( 3 , ( " wins_processing_traverse_fn: tombstoning %s \n " ,
nmb_namestr ( & namerec - > name ) ) ) ;
store_record = True ;
goto done ;
case WINS_TOMBSTONED :
DEBUG ( 3 , ( " wins_processing_traverse_fn: deleting %s \n " ,
nmb_namestr ( & namerec - > name ) ) ) ;
remove_name_from_wins_namelist ( namerec ) ;
goto done ;
}
} else {
2007-06-12 05:45:40 +04:00
switch ( namerec - > data . wins_flags & WINS_STATE_MASK ) {
2005-12-07 02:06:38 +03:00
case WINS_ACTIVE :
/* that's not as MS says it should be */
namerec - > data . wins_flags & = ~ WINS_STATE_MASK ;
namerec - > data . wins_flags | = WINS_TOMBSTONED ;
namerec - > data . death_time = t + EXTINCTION_TIMEOUT ;
DEBUG ( 3 , ( " wins_processing_traverse_fn: tombstoning %s \n " ,
nmb_namestr ( & namerec - > name ) ) ) ;
store_record = True ;
goto done ;
case WINS_TOMBSTONED :
DEBUG ( 3 , ( " wins_processing_traverse_fn: deleting %s \n " ,
nmb_namestr ( & namerec - > name ) ) ) ;
remove_name_from_wins_namelist ( namerec ) ;
goto done ;
case WINS_RELEASED :
DEBUG ( 0 , ( " wins_processing_traverse_fn: %s is in released state and \
we are not the wins owner ! \ n " , nmb_namestr(&namerec->name)));
goto done ;
}
}
}
done :
if ( store_record ) {
wins_store_changed_namerec ( namerec ) ;
}
SAFE_FREE ( namerec - > data . ip ) ;
SAFE_FREE ( namerec ) ;
return 0 ;
}
/*******************************************************************
Time dependent wins processing .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-12-13 17:16:07 +03:00
void initiate_wins_processing ( time_t t )
{
2002-01-26 01:50:15 +03:00
static time_t lasttime = 0 ;
2005-12-07 02:06:38 +03:00
if ( ! lasttime ) {
2002-01-26 01:50:15 +03:00
lasttime = t ;
2005-12-07 02:06:38 +03:00
}
if ( t - lasttime < 20 ) {
2002-01-26 01:50:15 +03:00
return ;
2005-12-07 02:06:38 +03:00
}
if ( ! lp_we_are_a_wins_server ( ) ) {
lasttime = t ;
return ;
}
tdb_traverse ( wins_tdb , wins_processing_traverse_fn , & t ) ;
2006-06-29 04:48:44 +04:00
wins_delete_all_tmp_in_memory_records ( ) ;
2005-12-07 02:06:38 +03:00
wins_write_database ( t , True ) ;
2002-01-26 01:50:15 +03:00
lasttime = t ;
2005-12-07 02:06:38 +03:00
}
2002-01-26 01:50:15 +03:00
2005-12-07 02:06:38 +03:00
/*******************************************************************
Write out one record .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-01-26 01:50:15 +03:00
2005-12-07 02:06:38 +03:00
void wins_write_name_record ( struct name_record * namerec , XFILE * fp )
{
int i ;
struct tm * tm ;
2002-01-26 01:50:15 +03:00
2005-12-07 02:06:38 +03:00
DEBUGADD ( 4 , ( " %-19s " , nmb_namestr ( & namerec - > name ) ) ) ;
if ( namerec - > data . death_time ! = PERMANENT_TTL ) {
char * ts , * nl ;
1997-12-13 17:16:07 +03:00
2005-12-07 02:06:38 +03:00
tm = localtime ( & namerec - > data . death_time ) ;
2006-06-15 01:36:49 +04:00
if ( ! tm ) {
return ;
}
2005-12-07 02:06:38 +03:00
ts = asctime ( tm ) ;
2006-06-15 01:36:49 +04:00
if ( ! ts ) {
return ;
}
2005-12-07 02:06:38 +03:00
nl = strrchr ( ts , ' \n ' ) ;
if ( NULL ! = nl ) {
* nl = ' \0 ' ;
2002-01-26 01:50:15 +03:00
}
2005-12-07 02:06:38 +03:00
DEBUGADD ( 4 , ( " TTL = %s " , ts ) ) ;
} else {
DEBUGADD ( 4 , ( " TTL = PERMANENT " ) ) ;
}
for ( i = 0 ; i < namerec - > data . num_ips ; i + + ) {
DEBUGADD ( 4 , ( " %15s " , inet_ntoa ( namerec - > data . ip [ i ] ) ) ) ;
2002-01-26 01:50:15 +03:00
}
2005-12-07 02:06:38 +03:00
DEBUGADD ( 4 , ( " %2x \n " , namerec - > data . nb_flags ) ) ;
1997-12-13 17:16:07 +03:00
2005-12-07 02:06:38 +03:00
if ( namerec - > data . source = = REGISTER_NAME ) {
unstring name ;
pull_ascii_nstring ( name , sizeof ( name ) , namerec - > name . name ) ;
x_fprintf ( fp , " \" %s#%02x \" %d " , name , namerec - > name . name_type , /* Ignore scope. */
( int ) namerec - > data . death_time ) ;
1997-12-13 17:16:07 +03:00
2005-12-07 02:06:38 +03:00
for ( i = 0 ; i < namerec - > data . num_ips ; i + + )
x_fprintf ( fp , " %s " , inet_ntoa ( namerec - > data . ip [ i ] ) ) ;
x_fprintf ( fp , " %2xR \n " , namerec - > data . nb_flags ) ;
}
1997-12-13 17:16:07 +03:00
}
/*******************************************************************
Write out the current WINS database .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
2005-12-07 02:06:38 +03:00
static int wins_writedb_traverse_fn ( TDB_CONTEXT * tdb , TDB_DATA kbuf , TDB_DATA dbuf , void * state )
{
struct name_record * namerec = NULL ;
XFILE * fp = ( XFILE * ) state ;
if ( kbuf . dsize ! = sizeof ( unstring ) + 1 ) {
return 0 ;
}
namerec = wins_record_to_name_record ( kbuf , dbuf ) ;
if ( ! namerec ) {
return 0 ;
}
wins_write_name_record ( namerec , fp ) ;
SAFE_FREE ( namerec - > data . ip ) ;
SAFE_FREE ( namerec ) ;
return 0 ;
}
2007-10-19 04:40:25 +04:00
void wins_write_database ( time_t t , bool background )
1997-12-13 17:16:07 +03:00
{
2005-12-07 02:06:38 +03:00
static time_t last_write_time = 0 ;
2007-11-20 02:15:09 +03:00
char * fname = NULL ;
char * fnamenew = NULL ;
2002-01-26 01:50:15 +03:00
2003-08-27 05:25:01 +04:00
XFILE * fp ;
2007-11-20 02:15:09 +03:00
2005-12-07 02:06:38 +03:00
if ( background ) {
if ( ! last_write_time ) {
last_write_time = t ;
}
if ( t - last_write_time < 120 ) {
return ;
}
}
if ( ! lp_we_are_a_wins_server ( ) ) {
2003-08-27 05:25:01 +04:00
return ;
2005-12-07 02:06:38 +03:00
}
2003-08-27 05:25:01 +04:00
/* We will do the writing in a child process to ensure that the parent doesn't block while this is done */
if ( background ) {
CatchChild ( ) ;
if ( sys_fork ( ) ) {
return ;
}
2005-12-07 02:06:38 +03:00
if ( tdb_reopen ( wins_tdb ) ) {
DEBUG ( 0 , ( " wins_write_database: tdb_reopen failed. Error was %s \n " ,
strerror ( errno ) ) ) ;
2007-06-21 03:24:18 +04:00
_exit ( 0 ) ;
2005-12-07 02:06:38 +03:00
return ;
}
2003-08-27 05:25:01 +04:00
}
2007-11-20 02:15:09 +03:00
if ( asprintf ( & fname , " %s/%s " , dyn_STATEDIR ( ) , WINS_LIST ) < 0 ) {
goto err_exit ;
}
/* This is safe as the 0 length means "don't expand". */
2003-08-27 05:25:01 +04:00
all_string_sub ( fname , " // " , " / " , 0 ) ;
2007-11-20 02:15:09 +03:00
if ( asprintf ( & fnamenew , " %s.%u " , fname , ( unsigned int ) sys_getpid ( ) ) < 0 ) {
goto err_exit ;
}
2003-08-27 05:25:01 +04:00
if ( ( fp = x_fopen ( fnamenew , O_WRONLY | O_CREAT , 0644 ) ) = = NULL ) {
DEBUG ( 0 , ( " wins_write_database: Can't open %s. Error was %s \n " , fnamenew , strerror ( errno ) ) ) ;
2007-11-20 02:15:09 +03:00
goto err_exit ;
2003-08-27 05:25:01 +04:00
}
DEBUG ( 4 , ( " wins_write_database: Dump of WINS name list. \n " ) ) ;
x_fprintf ( fp , " VERSION %d %u \n " , WINS_VERSION , 0 ) ;
2007-11-20 02:15:09 +03:00
2005-12-07 02:06:38 +03:00
tdb_traverse ( wins_tdb , wins_writedb_traverse_fn , fp ) ;
2003-08-27 05:25:01 +04:00
x_fclose ( fp ) ;
chmod ( fnamenew , 0644 ) ;
unlink ( fname ) ;
rename ( fnamenew , fname ) ;
2007-11-20 02:15:09 +03:00
err_exit :
SAFE_FREE ( fname ) ;
SAFE_FREE ( fnamenew ) ;
2003-08-27 05:25:01 +04:00
if ( background ) {
_exit ( 0 ) ;
}
2002-01-26 01:50:15 +03:00
}
2005-12-07 02:06:38 +03:00
#if 0
Until winsrepl is done .
2002-01-26 01:50:15 +03:00
/****************************************************************************
2003-08-27 05:25:01 +04:00
Process a internal Samba message receiving a wins record .
2002-01-26 01:50:15 +03:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2003-08-27 05:25:01 +04:00
2007-05-20 01:53:28 +04:00
void nmbd_wins_new_entry ( struct messaging_context * msg ,
void * private_data ,
uint32_t msg_type ,
struct server_id server_id ,
DATA_BLOB * data )
2002-01-26 01:50:15 +03:00
{
WINS_RECORD * record ;
struct name_record * namerec = NULL ;
struct name_record * new_namerec = NULL ;
struct nmb_name question ;
2007-10-19 04:40:25 +04:00
bool overwrite = False ;
2007-11-04 08:34:46 +03:00
struct in_addr our_fake_ip ;
2002-01-26 01:50:15 +03:00
int i ;
2007-11-04 08:34:46 +03:00
( void ) interpret_addr2 ( & our_fake_ip , " 0.0.0.0 " ) ;
2005-12-07 02:06:38 +03:00
if ( buf = = NULL ) {
2002-01-26 01:50:15 +03:00
return ;
2005-12-07 02:06:38 +03:00
}
2002-01-26 01:50:15 +03:00
2003-08-27 05:25:01 +04:00
/* Record should use UNIX codepage. Ensure this is so in the wrepld code. JRA. */
2002-01-26 01:50:15 +03:00
record = ( WINS_RECORD * ) buf ;
2003-08-27 05:25:01 +04:00
make_nmb_name ( & question , record - > name , record - > type ) ;
2002-01-26 01:50:15 +03:00
namerec = find_name_on_subnet ( wins_server_subnet , & question , FIND_ANY_NAME ) ;
/* record doesn't exist, add it */
if ( namerec = = NULL ) {
DEBUG ( 3 , ( " nmbd_wins_new_entry: adding new replicated record: %s<%02x> for wins server: %s \n " ,
record - > name , record - > type , inet_ntoa ( record - > wins_ip ) ) ) ;
2005-12-07 02:06:38 +03:00
new_namerec = add_name_to_subnet ( wins_server_subnet ,
record - > name ,
record - > type ,
record - > nb_flags ,
EXTINCTION_INTERVAL ,
REGISTER_NAME ,
record - > num_ips ,
record - > ip ) ;
2002-01-26 01:50:15 +03:00
if ( new_namerec ! = NULL ) {
update_wins_owner ( new_namerec , record - > wins_ip ) ;
update_wins_flag ( new_namerec , record - > wins_flags ) ;
new_namerec - > data . id = record - > id ;
wins_server_subnet - > namelist_changed = True ;
}
}
/* check if we have a conflict */
if ( namerec ! = NULL ) {
/* both records are UNIQUE */
if ( namerec - > data . wins_flags & WINS_UNIQUE & & record - > wins_flags & WINS_UNIQUE ) {
/* the database record is a replica */
2007-10-25 01:16:54 +04:00
if ( ! ip_equal_v4 ( namerec - > data . wins_ip , our_fake_ip ) ) {
2002-01-26 01:50:15 +03:00
if ( namerec - > data . wins_flags & WINS_ACTIVE & & record - > wins_flags & WINS_TOMBSTONED ) {
2007-10-25 01:16:54 +04:00
if ( ip_equal_v4 ( namerec - > data . wins_ip , record - > wins_ip ) )
2002-01-26 01:50:15 +03:00
overwrite = True ;
} else
overwrite = True ;
} else {
/* we are the wins owner of the database record */
/* the 2 records have the same IP address */
2007-10-25 01:16:54 +04:00
if ( ip_equal_v4 ( namerec - > data . ip [ 0 ] , record - > ip [ 0 ] ) ) {
2002-01-26 01:50:15 +03:00
if ( namerec - > data . wins_flags & WINS_ACTIVE & & record - > wins_flags & WINS_TOMBSTONED )
get_global_id_and_update ( & namerec - > data . id , True ) ;
else
overwrite = True ;
} else {
/* the 2 records have different IP address */
if ( namerec - > data . wins_flags & WINS_ACTIVE ) {
if ( record - > wins_flags & WINS_TOMBSTONED )
get_global_id_and_update ( & namerec - > data . id , True ) ;
if ( record - > wins_flags & WINS_ACTIVE )
/* send conflict challenge to the replica node */
;
} else
overwrite = True ;
}
}
}
/* the replica is a standard group */
if ( record - > wins_flags & WINS_NGROUP | | record - > wins_flags & WINS_SGROUP ) {
/* if the database record is unique and active force a name release */
if ( namerec - > data . wins_flags & WINS_UNIQUE )
/* send a release name to the unique node */
;
overwrite = True ;
}
/* the replica is a special group */
if ( record - > wins_flags & WINS_SGROUP & & namerec - > data . wins_flags & WINS_SGROUP ) {
if ( namerec - > data . wins_flags & WINS_ACTIVE ) {
for ( i = 0 ; i < record - > num_ips ; i + + )
if ( ! find_ip_in_name_record ( namerec , record - > ip [ i ] ) )
add_ip_to_name_record ( namerec , record - > ip [ i ] ) ;
2003-08-27 05:25:01 +04:00
} else {
2002-01-26 01:50:15 +03:00
overwrite = True ;
2003-08-27 05:25:01 +04:00
}
2002-01-26 01:50:15 +03:00
}
/* the replica is a multihomed host */
/* I'm giving up on multi homed. Too much complex to understand */
if ( record - > wins_flags & WINS_MHOMED ) {
2002-10-03 21:30:57 +04:00
if ( ! ( namerec - > data . wins_flags & WINS_ACTIVE ) ) {
if ( ! ( namerec - > data . wins_flags & WINS_RELEASED ) & & ! ( namerec - > data . wins_flags & WINS_NGROUP ) )
2002-01-26 01:50:15 +03:00
overwrite = True ;
}
else {
2007-10-25 01:16:54 +04:00
if ( ip_equal_v4 ( record - > wins_ip , namerec - > data . wins_ip ) )
2002-01-26 01:50:15 +03:00
overwrite = True ;
2007-10-25 01:16:54 +04:00
if ( ip_equal_v4 ( namerec - > data . wins_ip , our_fake_ip ) )
2002-01-26 01:50:15 +03:00
if ( namerec - > data . wins_flags & WINS_UNIQUE )
get_global_id_and_update ( & namerec - > data . id , True ) ;
}
if ( record - > wins_flags & WINS_ACTIVE & & namerec - > data . wins_flags & WINS_ACTIVE )
if ( namerec - > data . wins_flags & WINS_UNIQUE | |
namerec - > data . wins_flags & WINS_MHOMED )
2007-10-25 01:16:54 +04:00
if ( ip_equal_v4 ( record - > wins_ip , namerec - > data . wins_ip ) )
2002-01-26 01:50:15 +03:00
overwrite = True ;
}
if ( overwrite = = False )
DEBUG ( 3 , ( " nmbd_wins_new_entry: conflict in adding record: %s<%02x> from wins server: %s \n " ,
record - > name , record - > type , inet_ntoa ( record - > wins_ip ) ) ) ;
else {
DEBUG ( 3 , ( " nmbd_wins_new_entry: replacing record: %s<%02x> from wins server: %s \n " ,
record - > name , record - > type , inet_ntoa ( record - > wins_ip ) ) ) ;
/* remove the old record and add a new one */
remove_name_from_namelist ( wins_server_subnet , namerec ) ;
new_namerec = add_name_to_subnet ( wins_server_subnet , record - > name , record - > type , record - > nb_flags ,
EXTINCTION_INTERVAL , REGISTER_NAME , record - > num_ips , record - > ip ) ;
if ( new_namerec ! = NULL ) {
update_wins_owner ( new_namerec , record - > wins_ip ) ;
update_wins_flag ( new_namerec , record - > wins_flags ) ;
new_namerec - > data . id = record - > id ;
wins_server_subnet - > namelist_changed = True ;
}
wins_server_subnet - > namelist_changed = True ;
}
}
1997-12-13 17:16:07 +03:00
}
2005-12-07 02:06:38 +03:00
# endif