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
1998-01-22 16:27:43 +03:00
Copyright ( C ) Jeremy Allison 1994 - 1998
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
the Free Software Foundation ; either version 2 of the License , or
( at your option ) any later version .
This program is distributed in the hope that it will be useful ,
but WITHOUT ANY WARRANTY ; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
GNU General Public License for more details .
You should have received a copy of the GNU General Public License
along with this program ; if not , write to the Free Software
Foundation , Inc . , 675 Mass Ave , Cambridge , MA 0213 9 , USA .
*/
# include "includes.h"
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
1997-12-13 17:16:07 +03:00
2002-01-26 01:50:15 +03:00
/****************************************************************************
change the wins owner address in the record .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void update_wins_owner ( struct name_record * namerec , struct in_addr wins_ip )
{
if ( namerec = = NULL )
return ;
namerec - > data . wins_ip = wins_ip ;
}
/****************************************************************************
create the wins flags based on the nb flags and the input value .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void update_wins_flag ( struct name_record * namerec , int flags )
{
if ( namerec = = NULL )
return ;
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 ) {
if ( namerec - > name . name_type = = 0x1C )
namerec - > data . wins_flags | = WINS_SGROUP ;
else
if ( namerec - > data . num_ips > 1 )
namerec - > data . wins_flags | = WINS_SGROUP ;
else
namerec - > data . wins_flags | = WINS_NGROUP ;
} else {
/* can be unique or multi-homed */
if ( namerec - > data . num_ips > 1 )
namerec - > data . wins_flags | = WINS_MHOMED ;
else
namerec - > data . wins_flags | = WINS_UNIQUE ;
}
/* the node type are the same bits */
namerec - > data . wins_flags | = namerec - > data . nb_flags & NB_NODETYPEMASK ;
/* the static bit is elsewhere */
if ( namerec - > data . death_time = = PERMANENT_TTL )
namerec - > data . wins_flags | = WINS_STATIC ;
/* 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 ) ) ;
}
/****************************************************************************
return the general ID value and increase it if requested
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void get_global_id_and_update ( SMB_BIG_UINT * current_id , BOOL update )
{
/*
* 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 ;
if ( update )
general_id + + ;
}
1999-12-13 16:27:58 +03:00
/****************************************************************************
possibly call the WINS hook external program when a WINS change is made
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
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
{
pstring command ;
char * cmd = lp_wins_hook ( ) ;
char * p ;
int i ;
if ( ! cmd | | ! * cmd ) return ;
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 ;
}
}
p = command ;
2001-04-09 00:22:39 +04:00
p + = slprintf ( p , sizeof ( command ) - 1 , " %s %s %s %02x %d " ,
1999-12-13 16:27:58 +03:00
cmd ,
operation ,
2003-08-23 01:41:50 +04:00
nmb_namestr ( & namerec - > name ) ,
1999-12-13 16:27:58 +03:00
namerec - > name . name_type ,
ttl ) ;
for ( i = 0 ; i < namerec - > data . num_ips ; i + + ) {
2001-04-09 00:22:39 +04:00
p + = slprintf ( p , sizeof ( command ) - ( p - command ) - 1 , " %s " , inet_ntoa ( namerec - > data . ip [ i ] ) ) ;
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 ) ;
1999-12-13 16:27:58 +03:00
}
1998-08-30 10:49:14 +04:00
1997-12-13 17:16:07 +03:00
/****************************************************************************
Determine if this packet should be allocated to the WINS server .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL packet_is_for_wins_server ( struct packet_struct * packet )
{
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. */
if ( nmb - > question . question_type ! = QUESTION_TYPE_NB_QUERY )
return False ;
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 ;
}
/****************************************************************************
Utility function to decide what ttl to give a register / refresh request .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int get_ttl_from_packet ( struct nmb_packet * nmb )
{
int ttl = nmb - > additional - > ttl ;
if ( ttl < lp_min_wins_ttl ( ) )
ttl = lp_min_wins_ttl ( ) ;
if ( ttl > lp_max_wins_ttl ( ) )
ttl = lp_max_wins_ttl ( ) ;
return ttl ;
}
/****************************************************************************
Load or create the WINS database .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL initialise_wins ( void )
{
2003-05-08 11:33:39 +04:00
time_t time_now = time ( NULL ) ;
XFILE * fp ;
pstring line ;
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
if ( ! lp_we_are_a_wins_server ( ) )
return True ;
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
add_samba_names_to_subnet ( wins_server_subnet ) ;
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
if ( ( fp = x_fopen ( lock_path ( WINS_LIST ) , O_RDONLY , 0 ) ) = = NULL )
{
DEBUG ( 2 , ( " initialise_wins: Can't open wins database file %s. Error was %s \n " ,
WINS_LIST , strerror ( errno ) ) ) ;
return True ;
}
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
while ( ! x_feof ( fp ) )
{
pstring name_str , ip_str , ttl_str , nb_flags_str ;
unsigned int num_ips ;
pstring name ;
struct in_addr * ip_list ;
int type = 0 ;
int nb_flags ;
int ttl ;
const char * ptr ;
char * p ;
BOOL got_token ;
BOOL was_ip ;
int i ;
unsigned hash ;
int version ;
/* Read a line from the wins.dat file. Strips whitespace
from the beginning and end of the line .
*/
if ( ! fgets_slash ( line , sizeof ( pstring ) , fp ) )
continue ;
if ( * line = = ' # ' )
continue ;
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 ;
}
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
ptr = line ;
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +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 .
*/
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
if ( ! next_token ( & ptr , name_str , NULL , sizeof ( name_str ) ) )
{
DEBUG ( 0 , ( " initialise_wins: Failed to parse name when parsing line %s \n " , line ) ) ;
continue ;
}
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
if ( ! next_token ( & ptr , ttl_str , NULL , sizeof ( ttl_str ) ) )
{
DEBUG ( 0 , ( " initialise_wins: Failed to parse time to live when parsing line %s \n " , line ) ) ;
continue ;
}
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
/*
* Determine the number of IP addresses per line .
*/
num_ips = 0 ;
do
{
got_token = next_token ( & ptr , ip_str , NULL , sizeof ( ip_str ) ) ;
was_ip = False ;
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
if ( got_token & & strchr ( ip_str , ' . ' ) )
{
num_ips + + ;
was_ip = True ;
}
} while ( got_token & & was_ip ) ;
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
if ( num_ips = = 0 )
{
DEBUG ( 0 , ( " initialise_wins: Missing IP address when parsing line %s \n " , line ) ) ;
continue ;
}
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
if ( ! got_token )
{
DEBUG ( 0 , ( " initialise_wins: Missing nb_flags when parsing line %s \n " , line ) ) ;
continue ;
}
/* Allocate the space for the ip_list. */
if ( ( ip_list = ( struct in_addr * ) malloc ( num_ips * sizeof ( struct in_addr ) ) ) = = NULL )
{
DEBUG ( 0 , ( " initialise_wins: Malloc fail ! \n " ) ) ;
return False ;
}
/* Reset and re-parse the line. */
ptr = line ;
next_token ( & ptr , name_str , NULL , sizeof ( name_str ) ) ;
next_token ( & ptr , ttl_str , NULL , sizeof ( ttl_str ) ) ;
for ( i = 0 ; i < num_ips ; i + + )
{
next_token ( & ptr , ip_str , NULL , sizeof ( ip_str ) ) ;
ip_list [ i ] = * interpret_addr2 ( ip_str ) ;
}
next_token ( & ptr , nb_flags_str , NULL , sizeof ( nb_flags_str ) ) ;
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +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 ) ;
continue ;
}
if ( nb_flags_str [ strlen ( nb_flags_str ) - 1 ] = = ' R ' )
nb_flags_str [ strlen ( nb_flags_str ) - 1 ] = ' \0 ' ;
/* Netbios name. # divides the name from the type (hex): netbios#xx */
pstrcpy ( name , name_str ) ;
if ( ( p = strchr ( name , ' # ' ) ) ! = NULL )
{
* p = 0 ;
sscanf ( p + 1 , " %x " , & type ) ;
}
/* 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 )
{
if ( ttl ! = PERMANENT_TTL )
ttl - = time_now ;
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +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 ) ) ;
2002-01-26 01:50:15 +03:00
2003-05-08 11:33:39 +04:00
( void ) add_name_to_subnet ( wins_server_subnet , name , type , nb_flags ,
ttl , REGISTER_NAME , num_ips , ip_list ) ;
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
}
else
{
DEBUG ( 4 , ( " initialise_wins: not adding name (ttl problem) %s#%02x ttl = %d first IP %s flags = %2x \n " ,
name , type , ttl , inet_ntoa ( ip_list [ 0 ] ) , nb_flags ) ) ;
}
SAFE_FREE ( ip_list ) ;
}
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +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 )
{
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 ;
if ( nmb - > header . nm_flags . authoritative & &
nmb - > header . response ) rdata [ 0 ] | = 0x4 ;
if ( nmb - > header . nm_flags . trunc ) rdata [ 0 ] | = 0x2 ;
if ( nmb - > header . nm_flags . recursion_desired ) rdata [ 0 ] | = 0x1 ;
if ( nmb - > header . nm_flags . recursion_available & &
nmb - > header . response ) rdata [ 1 ] | = 0x80 ;
if ( nmb - > header . nm_flags . bcast ) rdata [ 1 ] | = 0x10 ;
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. */
}
/****************************************************************************
Send a WINS name registration response .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void send_wins_name_registration_response ( int rcode , int ttl , struct packet_struct * p )
{
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. */
}
/***********************************************************************
Deal with a name refresh request to a WINS server .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void wins_process_name_refresh_request ( struct subnet_record * subrec ,
struct packet_struct * p )
{
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
BOOL bcast = nmb - > header . nm_flags . bcast ;
uint16 nb_flags = get_nb_flags ( nmb - > additional - > rdata ) ;
BOOL group = ( nb_flags & NB_GROUP ) ? True : False ;
struct name_record * namerec = NULL ;
int ttl = get_ttl_from_packet ( nmb ) ;
struct in_addr from_ip ;
2002-01-26 01:50:15 +03:00
struct in_addr our_fake_ip = * interpret_addr2 ( " 0.0.0.0 " ) ;
1997-12-13 17:16:07 +03:00
putip ( ( char * ) & from_ip , & nmb - > additional - > rdata [ 2 ] ) ;
if ( bcast )
{
/*
* We should only get unicast name refresh packets here .
* Anyone trying to refresh broadcast should not be going to a WINS
* server . Log an error here .
*/
DEBUG ( 0 , ( " wins_process_name_refresh_request: broadcast name refresh request \
received for name % s from IP % s on subnet % s . Error - should not be sent to WINS server \ n " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) , subrec - > subnet_name ) ) ;
1997-12-13 17:16:07 +03:00
return ;
}
DEBUG ( 3 , ( " wins_process_name_refresh_request: Name refresh 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
/*
* See if the name already exists .
*/
namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ;
/*
* If this is a refresh request and the name doesn ' t exist then
1998-08-31 13:38:50 +04:00
* treat it like a registration request . This allows us to recover
* from errors ( tridge )
1997-12-13 17:16:07 +03:00
*/
if ( namerec = = NULL )
{
DEBUG ( 3 , ( " wins_process_name_refresh_request: Name refresh for name %s and \
1998-11-14 04:04:13 +03:00
the name does not exist . Treating as registration . \ n " , nmb_namestr(question) ));
1998-08-31 13:38:50 +04:00
wins_process_name_registration_request ( subrec , p ) ;
1997-12-13 17:16:07 +03:00
return ;
}
2002-01-26 01:50:15 +03:00
/*
* if the name is present but not active ,
* simply remove it and treat the request
* as a registration
*/
if ( namerec ! = NULL & & ! WINS_STATE_ACTIVE ( namerec ) )
{
DEBUG ( 5 , ( " wins_process_name_refresh_request: Name (%s) in WINS was \
not active - removing it . \ n " , nmb_namestr(question) ));
remove_name_from_namelist ( subrec , namerec ) ;
namerec = NULL ;
wins_process_name_registration_request ( subrec , p ) ;
return ;
}
1997-12-13 17:16:07 +03:00
/*
* Check that the group bits for the refreshing name and the
* name in our database match .
*/
if ( ( namerec ! = NULL ) & & ( ( group & & ! NAME_GROUP ( namerec ) ) | | ( ! group & & NAME_GROUP ( namerec ) ) ) )
{
DEBUG ( 3 , ( " wins_process_name_refresh_request: Name %s group bit = %s \
1998-11-14 04:04:13 +03:00
does not match group bit in WINS for this name . \ n " , nmb_namestr(question), group ? " True " : " False " ));
1997-12-13 17:16:07 +03:00
send_wins_name_registration_response ( RFS_ERR , 0 , p ) ;
return ;
}
/*
* 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 .
*/
if ( ( ! group | | ( group & & ( question - > name_type = = 0x1c ) ) ) & & find_ip_in_name_record ( namerec , from_ip ) )
{
/*
* Update the ttl .
*/
update_name_ttl ( namerec , ttl ) ;
2002-01-26 01:50:15 +03:00
/*
* if the record is a replica :
* we take ownership and update the version ID .
*/
if ( ! ip_equal ( namerec - > data . wins_ip , our_fake_ip ) ) {
update_wins_owner ( namerec , our_fake_ip ) ;
get_global_id_and_update ( & namerec - > data . id , True ) ;
}
1997-12-13 17:16:07 +03:00
send_wins_name_registration_response ( 0 , ttl , p ) ;
1999-12-13 16:27:58 +03:00
wins_hook ( " refresh " , namerec , ttl ) ;
1997-12-13 17:16:07 +03:00
return ;
}
else if ( group )
{
/*
* Normal groups are all registered with an IP address of 255.255 .255 .255
* so we can ' t search for the IP address .
*/
update_name_ttl ( namerec , ttl ) ;
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 .
*/
DEBUG ( 3 , ( " wins_process_name_refresh_request: Name refresh for name %s with IP %s and \
1998-11-14 04:04:13 +03:00
is IP is not known to the name . \ n " , nmb_namestr(question), inet_ntoa(from_ip) ));
1997-12-13 17:16:07 +03:00
send_wins_name_registration_response ( RFS_ERR , 0 , p ) ;
return ;
}
}
/***********************************************************************
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 )
{
struct packet_struct * orig_reg_packet ;
memcpy ( ( char * ) & orig_reg_packet , userdata - > data , sizeof ( struct packet_struct * ) ) ;
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
send_wins_name_registration_response ( RFS_ERR , 0 , orig_reg_packet ) ;
orig_reg_packet - > locked = False ;
free_packet ( orig_reg_packet ) ;
}
/***********************************************************************
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 )
{
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 ) ;
1998-06-09 05:56:18 +04:00
if ( ( namerec ! = NULL )
& & ( namerec - > data . source = = REGISTER_NAME )
& & ip_equal ( rrec - > packet - > ip , * namerec - > data . ip ) )
1997-12-13 17:16:07 +03:00
{
remove_name_from_namelist ( subrec , namerec ) ;
namerec = NULL ;
}
if ( namerec = = NULL )
wins_process_name_registration_request ( subrec , orig_reg_packet ) ;
else
DEBUG ( 2 , ( " wins_register_query_fail: The state of the WINS database changed between \
1998-11-14 04:04:13 +03:00
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
orig_reg_packet - > locked = False ;
free_packet ( orig_reg_packet ) ;
}
/***********************************************************************
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 )
{
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
BOOL bcast = nmb - > header . nm_flags . bcast ;
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 ;
1999-12-13 16:27:58 +03:00
BOOL registering_group_name = ( nb_flags & NB_GROUP ) ? True : False ;
2002-01-26 01:50:15 +03:00
struct in_addr our_fake_ip = * interpret_addr2 ( " 0.0.0.0 " ) ;
1997-12-13 17:16:07 +03: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 \
received for name % s from IP % s on subnet % s . Error - should not be sent to WINS server \ n " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) , subrec - > subnet_name ) ) ;
1997-12-13 17:16:07 +03:00
return ;
}
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
/*
* See if the name already exists .
*/
namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ;
2002-01-26 01:50:15 +03: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 \
not active - removing it . \ n " , nmb_namestr(question) ));
remove_name_from_namelist ( subrec , namerec ) ;
namerec = NULL ;
}
1997-12-13 17:16:07 +03: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 .
*/
1998-06-09 05:56:18 +04:00
if ( ( namerec ! = NULL )
& & ( ( namerec - > data . source = = DNS_NAME )
| | ( namerec - > data . source = = DNSFAIL_NAME ) ) )
1997-12-13 17:16:07 +03:00
{
1998-06-09 05:56:18 +04:00
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) ));
1998-06-09 05:56:18 +04:00
remove_name_from_namelist ( subrec , namerec ) ;
1997-12-13 17:16:07 +03:00
namerec = NULL ;
}
/*
* Reject if the name exists and is not a REGISTER_NAME .
* ( ie . Don ' t allow any static names to be overwritten .
*/
1998-06-09 05:56:18 +04:00
if ( ( namerec ! = NULL ) & & ( namerec - > data . source ! = REGISTER_NAME ) )
1997-12-13 17:16:07 +03:00
{
1998-06-09 05:56:18 +04:00
DEBUG ( 3 , ( " wins_process_name_registration_request: Attempt \
to register name % s . Name already exists in WINS with source type % d . \ n " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) , namerec - > data . source ) ) ;
1997-12-13 17:16:07 +03:00
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 .
*/
if ( registering_group_name & & ( question - > name_type ! = 0x1c ) )
from_ip = * interpret_addr2 ( " 255.255.255.255 " ) ;
/*
* 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) ));
1997-12-13 17:16:07 +03:00
send_wins_name_registration_response ( 0 , ttl , p ) ;
return ;
}
/*
* Next two cases are the ' if statement ' mentioned above .
*/
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 " ,
1998-11-14 04:04:13 +03:00
inet_ntoa ( from_ip ) , nmb_namestr ( question ) ) ) ;
1997-12-13 17:16:07 +03:00
/*
* Check the ip address is not already in the group .
*/
2002-01-26 01:50:15 +03:00
if ( ! find_ip_in_name_record ( namerec , from_ip ) ) {
1997-12-13 17:16:07 +03:00
add_ip_to_name_record ( namerec , from_ip ) ;
2002-01-26 01:50:15 +03:00
/* 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 ) ;
}
1997-12-13 17:16:07 +03:00
update_name_ttl ( namerec , ttl ) ;
send_wins_name_registration_response ( 0 , ttl , p ) ;
return ;
}
else
{
/*
* If we are adding a unique name , the name exists in the WINS db
* and is a group name then reject the registration .
2002-01-26 01:50:15 +03:00
*
* explanation : groups have a higher priority than unique names .
1997-12-13 17:16:07 +03:00
*/
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) ));
1997-12-13 17:16:07 +03: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 ) ) )
{
if ( ! ismyip ( from_ip ) )
{
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) )) ;
1997-12-13 17:16:07 +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 ) ;
send_wins_name_registration_response ( 0 , ttl , p ) ;
1999-12-13 16:27:58 +03:00
wins_hook ( " refresh " , namerec , ttl ) ;
1997-12-13 17:16:07 +03:00
return ;
}
}
/*
* If the name exists and it is a unique registration and the registering IP
2002-01-26 01:50:15 +03:00
* 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
1997-12-13 17:16:07 +03:00
*/
1998-06-09 05:56:18 +04:00
if ( ! registering_group_name
& & ( namerec ! = NULL )
& & ( namerec - > data . num_ips = = 1 )
2002-01-26 01:50:15 +03:00
& & ip_equal ( namerec - > data . ip [ 0 ] , from_ip )
& & ip_equal ( namerec - > data . wins_ip , our_fake_ip ) )
1997-12-13 17:16:07 +03:00
{
1998-06-09 05:56:18 +04:00
update_name_ttl ( namerec , ttl ) ;
send_wins_name_registration_response ( 0 , ttl , p ) ;
1999-12-13 16:27:58 +03:00
wins_hook ( " refresh " , namerec , ttl ) ;
1997-12-13 17:16:07 +03:00
return ;
}
/*
* Finally if the name exists do a query to the registering machine
* to see if they still claim to have the name .
*/
1998-06-09 05:56:18 +04:00
if ( namerec ! = NULL )
1997-12-13 17:16:07 +03:00
{
2000-01-29 02:47:31 +03:00
long * ud [ ( sizeof ( struct userdata_struct ) + sizeof ( struct packet_struct * ) ) / sizeof ( long * ) + 1 ] ;
1998-01-07 09:21:56 +03:00
struct userdata_struct * userdata = ( struct userdata_struct * ) ud ;
1997-12-13 17:16:07 +03:00
/*
* 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 * ) ) ;
/*
1998-04-21 00:32:50 +04:00
* 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 .
1997-12-13 17:16:07 +03:00
*/
1998-06-09 05:56:18 +04:00
query_name_from_wins_server ( * namerec - > data . ip ,
question - > name ,
question - > name_type ,
wins_register_query_success ,
wins_register_query_fail ,
userdata ) ;
1997-12-13 17:16:07 +03:00
return ;
}
/*
* Name did not exist - add it .
*/
1998-06-23 12:15:05 +04:00
( void ) add_name_to_subnet ( subrec , question - > name , question - > name_type ,
2002-01-26 01:50:15 +03:00
nb_flags , ttl , REGISTER_NAME , 1 , & from_ip ) ;
1999-12-13 16:27:58 +03:00
if ( ( namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ) ) {
2002-01-26 01:50:15 +03:00
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 ) ;
1999-12-13 16:27:58 +03:00
}
1997-12-13 17:16:07 +03:00
send_wins_name_registration_response ( 0 , ttl , p ) ;
}
/***********************************************************************
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 )
{
struct packet_struct * orig_reg_packet ;
struct nmb_packet * nmb ;
struct name_record * namerec = NULL ;
struct in_addr from_ip ;
int ttl ;
2002-01-26 01:50:15 +03:00
struct in_addr our_fake_ip = * interpret_addr2 ( " 0.0.0.0 " ) ;
1997-12-13 17:16:07 +03: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 ) ;
2002-01-26 01:50:15 +03:00
if ( ( namerec = = NULL ) | | ( namerec - > data . source ! = REGISTER_NAME ) | | ! WINS_STATE_ACTIVE ( namerec ) )
1997-12-13 17:16:07 +03:00
{
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) ));
1997-12-13 17:16:07 +03:00
send_wins_name_registration_response ( RFS_ERR , 0 , orig_reg_packet ) ;
1998-06-26 03:51:28 +04:00
orig_reg_packet - > locked = False ;
free_packet ( orig_reg_packet ) ;
1997-12-13 17:16:07 +03:00
return ;
}
if ( ! find_ip_in_name_record ( namerec , from_ip ) )
add_ip_to_name_record ( namerec , from_ip ) ;
2002-01-26 01:50:15 +03:00
get_global_id_and_update ( & namerec - > data . id , True ) ;
update_wins_owner ( namerec , our_fake_ip ) ;
update_wins_flag ( namerec , WINS_ACTIVE ) ;
1997-12-13 17:16:07 +03:00
update_name_ttl ( namerec , ttl ) ;
send_wins_name_registration_response ( 0 , ttl , orig_reg_packet ) ;
1999-12-13 16:27:58 +03:00
wins_hook ( " add " , namerec , ttl ) ;
1997-12-13 17:16:07 +03:00
1998-06-26 03:51:28 +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 )
{
struct userdata_struct * userdata = rrec - > userdata ;
struct packet_struct * orig_reg_packet ;
memcpy ( ( char * ) & orig_reg_packet , userdata - > data , sizeof ( struct packet_struct * ) ) ;
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) ));
1997-12-13 17:16:07 +03:00
send_wins_name_registration_response ( RFS_ERR , 0 , orig_reg_packet ) ;
1998-06-26 03:51:28 +04:00
orig_reg_packet - > locked = False ;
free_packet ( orig_reg_packet ) ;
1997-12-13 17:16:07 +03:00
return ;
}
/***********************************************************************
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 )
{
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
BOOL bcast = nmb - > header . nm_flags . bcast ;
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 ;
2002-01-26 01:50:15 +03:00
BOOL group = ( nb_flags & NB_GROUP ) ? True : False ;
struct in_addr our_fake_ip = * interpret_addr2 ( " 0.0.0.0 " ) ;
1997-12-13 17:16:07 +03: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 \
received for name % s from IP % s on subnet % s . Error - should not be sent to WINS server \ n " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) , subrec - > subnet_name ) ) ;
1997-12-13 17:16:07 +03:00
return ;
}
/*
* Only unique names should be registered multihomed .
*/
if ( group )
{
DEBUG ( 0 , ( " wins_process_multihomed_name_registration_request: group name registration request \
received for name % s from IP % s on subnet % s . Errror - group names should not be multihomed . \ n " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) , subrec - > subnet_name ) ) ;
1997-12-13 17:16:07 +03:00
return ;
}
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
/*
* Deal with policy regarding 0x1d names .
*/
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) ));
1997-12-13 17:16:07 +03: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 ) ;
2002-07-15 14:35:28 +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_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 ;
}
1997-12-13 17:16:07 +03: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 .
*/
1998-06-09 05:56:18 +04:00
if ( ( namerec ! = NULL )
& & ( ( namerec - > data . source = = DNS_NAME )
| | ( namerec - > data . source = = DNSFAIL_NAME ) ) )
1997-12-13 17:16:07 +03:00
{
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) ));
1997-12-13 17:16:07 +03: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 .
*/
1998-06-09 05:56:18 +04:00
if ( ( namerec ! = NULL ) & & ( namerec - > data . source ! = REGISTER_NAME ) )
1997-12-13 17:16:07 +03:00
{
1998-06-09 05:56:18 +04:00
DEBUG ( 3 , ( " wins_process_multihomed_name_registration_request: Attempt \
to register name % s . Name already exists in WINS with source type % d . \ n " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) , namerec - > data . source ) ) ;
1997-12-13 17:16:07 +03:00
send_wins_name_registration_response ( RFS_ERR , 0 , p ) ;
return ;
}
/*
2002-01-26 01:50:15 +03:00
* Reject if the name exists and is a GROUP name and is active .
1997-12-13 17:16:07 +03:00
*/
2002-01-26 01:50:15 +03:00
if ( ( namerec ! = NULL ) & & NAME_GROUP ( namerec ) & & WINS_STATE_ACTIVE ( namerec ) )
1997-12-13 17:16:07 +03:00
{
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) ));
1997-12-13 17:16:07 +03: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 ) ) )
{
if ( ! ismyip ( from_ip ) )
{
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) )) ;
1997-12-13 17:16:07 +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 . Ensure the IP is in the record and
2002-01-26 01:50:15 +03:00
* update the ttl . Update the version ID to force replication .
1997-12-13 17:16:07 +03:00
*/
1999-12-13 16:27:58 +03:00
if ( ! find_ip_in_name_record ( namerec , from_ip ) ) {
2002-01-26 01:50:15 +03:00
get_global_id_and_update ( & namerec - > data . id , True ) ;
update_wins_owner ( namerec , our_fake_ip ) ;
update_wins_flag ( namerec , WINS_ACTIVE ) ;
1999-12-13 16:27:58 +03:00
add_ip_to_name_record ( namerec , from_ip ) ;
wins_hook ( " add " , namerec , ttl ) ;
} else {
wins_hook ( " refresh " , namerec , ttl ) ;
}
update_name_ttl ( namerec , ttl ) ;
send_wins_name_registration_response ( 0 , ttl , p ) ;
return ;
1997-12-13 17:16:07 +03:00
}
}
1998-01-29 11:25:46 +03:00
/*
2002-01-26 01:50:15 +03:00
* If the name exists and is active , check if the IP address is already registered
1998-01-29 11:25:46 +03:00
* to that name . If so then update the ttl and reply success .
*/
2002-01-26 01:50:15 +03:00
if ( ( namerec ! = NULL ) & & find_ip_in_name_record ( namerec , from_ip ) & & WINS_STATE_ACTIVE ( namerec ) )
1998-01-29 11:25:46 +03:00
{
update_name_ttl ( namerec , ttl ) ;
2002-01-26 01:50:15 +03:00
/*
* If it ' s a replica , we need to become the wins owner
* to force the replication
*/
if ( ! ip_equal ( namerec - > data . wins_ip , our_fake_ip ) ) {
get_global_id_and_update ( & namerec - > data . id , True ) ;
update_wins_owner ( namerec , our_fake_ip ) ;
update_wins_flag ( namerec , WINS_ACTIVE ) ;
}
1998-01-29 11:25:46 +03:00
send_wins_name_registration_response ( 0 , ttl , p ) ;
1999-12-13 16:27:58 +03:00
wins_hook ( " refresh " , namerec , ttl ) ;
1998-01-29 11:25:46 +03:00
return ;
}
1997-12-13 17:16:07 +03:00
/*
* If the name exists do a query to the owner
* to see if they still want the name .
*/
if ( namerec ! = NULL )
{
2000-01-29 02:47:31 +03:00
long * ud [ ( sizeof ( struct userdata_struct ) + sizeof ( struct packet_struct * ) ) / sizeof ( long * ) + 1 ] ;
1998-01-07 09:21:56 +03:00
struct userdata_struct * userdata = ( struct userdata_struct * ) ud ;
1997-12-13 17:16:07 +03:00
/*
* 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 * ) ) ;
1998-06-26 03:51:28 +04:00
/*
* 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 .
2000-03-27 03:16:07 +04:00
*
* Note that this packet is sent to the current owner of the name ,
* not the person who sent the packet
1997-12-13 17:16:07 +03:00
*/
2000-03-27 03:16:07 +04:00
query_name_from_wins_server ( namerec - > data . ip [ 0 ] ,
1998-06-26 03:51:28 +04:00
question - > name ,
question - > name_type ,
wins_multihomed_register_query_success ,
wins_multihomed_register_query_fail ,
userdata ) ;
1997-12-13 17:16:07 +03:00
return ;
}
/*
* Name did not exist - add it .
*/
1998-06-23 12:15:05 +04:00
( void ) add_name_to_subnet ( subrec , question - > name , question - > name_type ,
2002-01-26 01:50:15 +03:00
nb_flags , ttl , REGISTER_NAME , 1 , & from_ip ) ;
1997-12-13 17:16:07 +03:00
1999-12-13 16:27:58 +03:00
if ( ( namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ) ) {
2002-01-26 01:50:15 +03:00
get_global_id_and_update ( & namerec - > data . id , True ) ;
update_wins_owner ( namerec , our_fake_ip ) ;
update_wins_flag ( namerec , WINS_ACTIVE ) ;
1999-12-13 16:27:58 +03:00
wins_hook ( " add " , namerec , ttl ) ;
}
1997-12-13 17:16:07 +03:00
send_wins_name_registration_response ( 0 , ttl , p ) ;
}
/***********************************************************************
Deal with the special name query for * < 1 b > .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void process_wins_dmb_query_request ( struct subnet_record * subrec ,
struct packet_struct * p )
{
struct name_record * namerec = NULL ;
char * prdata ;
int num_ips ;
/*
2002-01-26 01:50:15 +03:00
* Go through all the ACTIVE names in the WINS db looking for those
1997-12-13 17:16:07 +03:00
* ending in < 1 b > . Use this to calculate the number of IP
* addresses we need to return .
*/
num_ips = 0 ;
1998-06-10 23:51:58 +04:00
for ( namerec = ( struct name_record * ) ubi_trFirst ( subrec - > namelist ) ;
namerec ;
namerec = ( struct name_record * ) ubi_trNext ( namerec ) )
1997-12-13 17:16:07 +03:00
{
2002-01-26 01:50:15 +03:00
if ( WINS_STATE_ACTIVE ( namerec ) & & namerec - > name . name_type = = 0x1b )
1998-06-09 05:56:18 +04:00
num_ips + = namerec - > data . num_ips ;
1997-12-13 17:16:07 +03: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 ;
}
if ( ( prdata = ( char * ) malloc ( num_ips * 6 ) ) = = NULL )
{
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 ;
1998-06-10 23:51:58 +04:00
for ( namerec = ( struct name_record * ) ubi_trFirst ( subrec - > namelist ) ;
namerec ;
namerec = ( struct name_record * ) ubi_trNext ( namerec ) )
1997-12-13 17:16:07 +03:00
{
2002-01-26 01:50:15 +03:00
if ( WINS_STATE_ACTIVE ( namerec ) & & namerec - > name . name_type = = 0x1b )
1997-12-13 17:16:07 +03:00
{
int i ;
1998-06-09 05:56:18 +04:00
for ( i = 0 ; i < namerec - > data . num_ips ; i + + )
1997-12-13 17:16:07 +03:00
{
1998-06-09 05:56:18 +04:00
set_nb_flags ( & prdata [ num_ips * 6 ] , namerec - > data . nb_flags ) ;
putip ( ( char * ) & prdata [ ( num_ips * 6 ) + 2 ] , & namerec - > data . ip [ i ] ) ;
1997-12-13 17:16:07 +03:00
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. */
2001-09-17 08:35:51 +04:00
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 )
{
char rdata [ 6 ] ;
char * prdata = rdata ;
int reply_data_len = 0 ;
int ttl = 0 ;
1998-08-30 12:45:23 +04:00
int i ;
1997-12-13 17:16:07 +03:00
1999-12-13 16:27:58 +03:00
memset ( rdata , ' \0 ' , 6 ) ;
1997-12-13 17:16:07 +03:00
if ( rcode = = 0 )
{
1998-06-09 05:56:18 +04:00
ttl = ( namerec - > data . death_time ! = PERMANENT_TTL ) ?
namerec - > data . death_time - p - > timestamp : lp_max_wins_ttl ( ) ;
1997-12-13 17:16:07 +03:00
/* 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 . */
1998-06-09 05:56:18 +04:00
if ( namerec - > data . num_ips = = 1 )
1997-12-13 17:16:07 +03:00
prdata = rdata ;
else
{
1998-06-09 05:56:18 +04:00
if ( ( prdata = ( char * ) malloc ( namerec - > data . num_ips * 6 ) ) = = NULL )
1997-12-13 17:16:07 +03:00
{
DEBUG ( 0 , ( " send_wins_name_query_response: malloc fail ! \n " ) ) ;
return ;
}
}
1998-08-30 12:45:23 +04:00
for ( i = 0 ; i < namerec - > data . num_ips ; i + + )
1997-12-13 17:16:07 +03:00
{
1998-06-09 05:56:18 +04:00
set_nb_flags ( & prdata [ i * 6 ] , namerec - > data . nb_flags ) ;
1998-08-30 12:45:23 +04:00
putip ( ( char * ) & prdata [ 2 + ( i * 6 ) ] , & namerec - > data . ip [ i ] ) ;
1997-12-13 17:16:07 +03:00
}
1998-08-30 12:45:23 +04:00
sort_query_replies ( prdata , i , p - > ip ) ;
reply_data_len = namerec - > data . num_ips * 6 ;
1997-12-13 17:16:07 +03:00
}
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. */
2001-09-17 08:35:51 +04:00
if ( prdata ! = rdata )
SAFE_FREE ( prdata ) ;
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 )
{
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
struct name_record * namerec = NULL ;
DEBUG ( 3 , ( " wins_process_name_query: name query for name %s from IP %s \n " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) , inet_ntoa ( p - > ip ) ) ) ;
1997-12-13 17:16:07 +03:00
/*
* 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 .
*/
if ( strequal ( question - > name , " * " ) & & ( 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 )
{
2002-01-26 01:50:15 +03:00
/*
* 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 ;
}
1997-12-13 17:16:07 +03:00
/*
* If it ' s a DNSFAIL_NAME then reply name not found .
*/
1998-06-09 05:56:18 +04:00
if ( namerec - > data . source = = DNSFAIL_NAME )
1997-12-13 17:16:07 +03:00
{
DEBUG ( 3 , ( " wins_process_name_query: name query for name %s returning DNS fail. \n " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) ) ) ;
1997-12-13 17:16:07 +03:00
send_wins_name_query_response ( NAM_ERR , p , namerec ) ;
return ;
}
/*
* If the name has expired then reply name not found .
*/
1998-06-09 05:56:18 +04:00
if ( ( namerec - > data . death_time ! = PERMANENT_TTL )
& & ( namerec - > data . death_time < p - > timestamp ) )
1997-12-13 17:16:07 +03:00
{
DEBUG ( 3 , ( " wins_process_name_query: name query for name %s - name expired. Returning fail. \n " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) ) ) ;
1997-12-13 17:16:07 +03:00
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 " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) , inet_ntoa ( namerec - > data . ip [ 0 ] ) ) ) ;
1997-12-13 17:16:07 +03:00
send_wins_name_query_response ( 0 , p , namerec ) ;
return ;
}
/*
* Name not found in WINS - try a dns query if it ' s a 0x20 name .
*/
1997-12-14 20:49:41 +03:00
if ( lp_dns_proxy ( ) & &
( ( question - > name_type = = 0x20 ) | | question - > name_type = = 0 ) )
1997-12-13 17:16:07 +03:00
{
DEBUG ( 3 , ( " wins_process_name_query: name query for name %s not found - doing dns lookup. \n " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) ) ) ;
1997-12-13 17:16:07 +03:00
queue_dns_query ( p , question , & namerec ) ;
return ;
}
/*
* Name not found - return error .
*/
send_wins_name_query_response ( NAM_ERR , p , NULL ) ;
}
/****************************************************************************
Send a WINS name release response .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void send_wins_name_release_response ( int rcode , struct packet_struct * p )
{
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. */
}
/***********************************************************************
Deal with a name release .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void wins_process_name_release_request ( struct subnet_record * subrec ,
struct packet_struct * p )
{
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
BOOL bcast = nmb - > header . nm_flags . bcast ;
uint16 nb_flags = get_nb_flags ( nmb - > additional - > rdata ) ;
struct name_record * namerec = NULL ;
struct in_addr from_ip ;
BOOL releasing_group_name = ( nb_flags & NB_GROUP ) ? True : False ; ;
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 \
received for name % s from IP % s on subnet % s . Error - should not be sent to WINS server \ n " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) , subrec - > subnet_name ) ) ;
1997-12-13 17:16:07 +03:00
return ;
}
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
/*
* Deal with policy regarding 0x1d names .
*/
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) ));
1997-12-13 17:16:07 +03:00
send_wins_name_release_response ( 0 , p ) ;
return ;
}
/*
* See if the name already exists .
*/
namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ;
1998-06-09 05:56:18 +04:00
if ( ( namerec = = NULL )
| | ( ( namerec ! = NULL ) & & ( namerec - > data . source ! = REGISTER_NAME ) ) )
1997-12-13 17:16:07 +03:00
{
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 \
release name % s as IP % s is not one of the known IP ' s for this name . \ n " ,
1998-11-14 04:04:13 +03:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) ) ) ;
1997-12-13 17:16:07 +03:00
send_wins_name_release_response ( NAM_ERR , p ) ;
return ;
}
2002-01-26 01:50:15 +03:00
/*
* 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 anymore active . \ n " ,
nmb_namestr ( question ) ) ) ;
send_wins_name_release_response ( NAM_ERR , p ) ;
return ;
}
2002-11-15 21:55:18 +03:00
/*
* 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 ) ) ) ;
send_wins_name_release_response ( 0 , p ) ;
return ;
}
1997-12-13 17:16:07 +03:00
/*
2002-01-26 01:50:15 +03:00
* Send a release response .
* Flag the name as released and update the ttl
1997-12-13 17:16:07 +03:00
*/
send_wins_name_release_response ( 0 , p ) ;
2002-01-26 01:50:15 +03:00
namerec - > data . wins_flags | = WINS_RELEASED ;
update_name_ttl ( namerec , EXTINCTION_INTERVAL ) ;
1997-12-13 17:16:07 +03:00
1999-12-13 16:27:58 +03:00
wins_hook ( " delete " , namerec , 0 ) ;
1997-12-13 17:16:07 +03:00
}
/*******************************************************************
WINS time dependent processing .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void initiate_wins_processing ( time_t t )
{
2002-01-26 01:50:15 +03:00
static time_t lasttime = 0 ;
struct name_record * namerec ;
struct name_record * next_namerec ;
struct in_addr our_fake_ip = * interpret_addr2 ( " 0.0.0.0 " ) ;
if ( ! lasttime )
lasttime = t ;
if ( t - lasttime < 20 )
return ;
lasttime = t ;
if ( ! lp_we_are_a_wins_server ( ) )
return ;
for ( namerec = ( struct name_record * ) ubi_trFirst ( wins_server_subnet - > namelist ) ;
namerec ;
namerec = next_namerec ) {
next_namerec = ( struct name_record * ) ubi_trNext ( namerec ) ;
if ( ( namerec - > data . death_time ! = PERMANENT_TTL )
& & ( namerec - > data . death_time < t ) ) {
if ( namerec - > data . source = = SELF_NAME ) {
DEBUG ( 3 , ( " expire_names_on_subnet: Subnet %s not expiring SELF name %s \n " ,
wins_server_subnet - > subnet_name , nmb_namestr ( & namerec - > name ) ) ) ;
namerec - > data . death_time + = 300 ;
namerec - > subnet - > namelist_changed = True ;
continue ;
}
/* handle records, samba is the wins owner */
if ( ip_equal ( namerec - > data . wins_ip , our_fake_ip ) ) {
switch ( namerec - > data . wins_flags | WINS_STATE_MASK ) {
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 , ( " initiate_wins_processing: expiring %s \n " , nmb_namestr ( & namerec - > name ) ) ) ;
break ;
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 , ( " initiate_wins_processing: tombstoning %s \n " , nmb_namestr ( & namerec - > name ) ) ) ;
break ;
case WINS_TOMBSTONED :
DEBUG ( 3 , ( " initiate_wins_processing: deleting %s \n " , nmb_namestr ( & namerec - > name ) ) ) ;
remove_name_from_namelist ( wins_server_subnet , namerec ) ;
break ;
}
} else {
switch ( namerec - > data . wins_flags | WINS_STATE_MASK ) {
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 , ( " initiate_wins_processing: tombstoning %s \n " , nmb_namestr ( & namerec - > name ) ) ) ;
case WINS_TOMBSTONED :
DEBUG ( 3 , ( " initiate_wins_processing: deleting %s \n " , nmb_namestr ( & namerec - > name ) ) ) ;
remove_name_from_namelist ( wins_server_subnet , namerec ) ;
break ;
case WINS_RELEASED :
DEBUG ( 0 , ( " initiate_wins_processing: %s is in released state and \
we are not the wins owner ! \ n " , nmb_namestr(&namerec->name)));
break ;
}
}
1997-12-13 17:16:07 +03:00
2002-01-26 01:50:15 +03:00
}
}
1997-12-13 17:16:07 +03:00
2002-01-26 01:50:15 +03:00
if ( wins_server_subnet - > namelist_changed )
wins_write_database ( True ) ;
1997-12-13 17:16:07 +03:00
2002-01-26 01:50:15 +03:00
wins_server_subnet - > namelist_changed = False ;
1997-12-13 17:16:07 +03:00
}
/*******************************************************************
Write out the current WINS database .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1998-09-17 10:36:08 +04:00
void wins_write_database ( BOOL background )
1997-12-13 17:16:07 +03:00
{
2003-05-08 11:33:39 +04:00
struct name_record * namerec ;
pstring fname , fnamenew ;
2002-01-26 01:50:15 +03:00
2003-05-08 11:33:39 +04:00
XFILE * fp ;
if ( ! lp_we_are_a_wins_server ( ) )
return ;
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +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 ;
}
}
1998-09-10 08:00:09 +04:00
2003-05-08 11:33:39 +04:00
slprintf ( fname , sizeof ( fname ) - 1 , " %s/%s " , lp_lockdir ( ) , WINS_LIST ) ;
all_string_sub ( fname , " // " , " / " , 0 ) ;
slprintf ( fnamenew , sizeof ( fnamenew ) - 1 , " %s.%u " , fname , ( unsigned int ) sys_getpid ( ) ) ;
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +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 ) ) ) ;
if ( background ) {
_exit ( 0 ) ;
}
return ;
}
1997-12-13 17:16:07 +03:00
2003-05-08 11:33:39 +04:00
DEBUG ( 4 , ( " wins_write_database: Dump of WINS name list. \n " ) ) ;
1998-08-30 09:43:59 +04:00
2003-05-08 11:33:39 +04:00
x_fprintf ( fp , " VERSION %d %u \n " , WINS_VERSION , 0 ) ;
for ( namerec
= ( struct name_record * ) ubi_trFirst ( wins_server_subnet - > namelist ) ;
namerec ;
namerec = ( struct name_record * ) ubi_trNext ( namerec ) )
{
int i ;
struct tm * tm ;
2002-01-26 01:50:15 +03:00
2003-05-08 11:33:39 +04:00
DEBUGADD ( 4 , ( " %-19s " , nmb_namestr ( & namerec - > name ) ) ) ;
2002-01-26 01:50:15 +03:00
2003-05-08 11:33:39 +04:00
if ( namerec - > data . death_time ! = PERMANENT_TTL )
{
char * ts , * nl ;
tm = LocalTime ( & namerec - > data . death_time ) ;
ts = asctime ( tm ) ;
nl = strrchr ( ts , ' \n ' ) ;
if ( NULL ! = nl )
* nl = ' \0 ' ;
DEBUGADD ( 4 , ( " TTL = %s " , ts ) ) ;
}
else
DEBUGADD ( 4 , ( " TTL = PERMANENT " ) ) ;
2002-01-26 01:50:15 +03:00
2003-05-08 11:33:39 +04:00
for ( i = 0 ; i < namerec - > data . num_ips ; i + + )
DEBUGADD ( 4 , ( " %15s " , inet_ntoa ( namerec - > data . ip [ i ] ) ) ) ;
DEBUGADD ( 4 , ( " %2x \n " , namerec - > data . nb_flags ) ) ;
2002-01-26 01:50:15 +03:00
2003-05-08 11:33:39 +04:00
if ( namerec - > data . source = = REGISTER_NAME )
{
x_fprintf ( fp , " \" %s#%02x \" %d " ,
namerec - > name . name , namerec - > name . name_type , /* Ignore scope. */
( int ) namerec - > data . death_time ) ;
2002-01-26 01:50:15 +03:00
2003-05-08 11:33:39 +04: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 ) ;
}
}
x_fclose ( fp ) ;
chmod ( fnamenew , 0644 ) ;
unlink ( fname ) ;
rename ( fnamenew , fname ) ;
if ( background ) {
_exit ( 0 ) ;
}
2002-01-26 01:50:15 +03:00
}
/****************************************************************************
process a internal Samba message receiving a wins record
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void nmbd_wins_new_entry ( int msg_type , pid_t src , void * buf , size_t len )
{
WINS_RECORD * record ;
struct name_record * namerec = NULL ;
struct name_record * new_namerec = NULL ;
struct nmb_name question ;
BOOL overwrite = False ;
struct in_addr our_fake_ip = * interpret_addr2 ( " 0.0.0.0 " ) ;
int i ;
if ( buf = = NULL )
return ;
record = ( WINS_RECORD * ) buf ;
ZERO_STRUCT ( question ) ;
memcpy ( question . name , record - > name , 16 ) ;
question . name_type = record - > type ;
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 ) ) ) ;
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 ;
}
}
/* 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 */
if ( ! ip_equal ( namerec - > data . wins_ip , our_fake_ip ) ) {
if ( namerec - > data . wins_flags & WINS_ACTIVE & & record - > wins_flags & WINS_TOMBSTONED ) {
if ( ip_equal ( namerec - > data . wins_ip , record - > wins_ip ) )
overwrite = True ;
} else
overwrite = True ;
} else {
/* we are the wins owner of the database record */
/* the 2 records have the same IP address */
if ( ip_equal ( namerec - > data . ip [ 0 ] , record - > ip [ 0 ] ) ) {
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 ] ) ;
}
else
overwrite = True ;
}
/* 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 {
if ( ip_equal ( record - > wins_ip , namerec - > data . wins_ip ) )
overwrite = True ;
if ( ip_equal ( namerec - > data . wins_ip , our_fake_ip ) )
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 )
if ( ip_equal ( record - > wins_ip , namerec - > data . wins_ip ) )
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
}