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 ) Andrew Tridgell 1994 - 1998
Copyright ( C ) Luke Kenneth Casson Leighton 1994 - 1998
2003-08-27 05:25:01 +04:00
Copyright ( C ) Jeremy Allison 1994 - 2003
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
This file contains all the code to process NetBIOS requests coming
in on port 137. It does not deal with the code needed to service
WINS server requests , but only broadcast and unicast requests .
*/
# include "includes.h"
2010-08-18 17:22:09 +04:00
# include "nmbd/nmbd.h"
1997-12-13 17:16:07 +03:00
/****************************************************************************
Send a name release response .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void send_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 ] ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
memcpy ( & rdata [ 0 ] , & nmb - > additional - > rdata [ 0 ] , 6 ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
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
}
/****************************************************************************
Process a name release packet on a broadcast subnet .
Ignore it if it ' s not one of our names .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void 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 in_addr owner_ip ;
struct nmb_name * question = & nmb - > question . question_name ;
2004-03-16 00:45:45 +03:00
unstring qname ;
2007-10-19 04:40:25 +04:00
bool bcast = nmb - > header . nm_flags . bcast ;
2015-04-30 06:14:34 +03:00
uint16_t 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 ;
int rcode = 0 ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
putip ( ( char * ) & owner_ip , & nmb - > additional - > rdata [ 2 ] ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
if ( ! bcast ) {
/* We should only get broadcast name release packets here.
Anyone trying to release unicast should be going to a WINS
server . If the code gets here , then either we are not a wins
server and they sent it anyway , or we are a WINS server and
the request was malformed . Either way , log an error here .
and send an error reply back .
*/
DEBUG ( 0 , ( " process_name_release_request: unicast name release request \
1997-12-13 17:16:07 +03:00
received for name % s from IP % s on subnet % s . Error - should be sent to WINS server \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( question ) , inet_ntoa ( owner_ip ) , subrec - > subnet_name ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
send_name_release_response ( FMT_ERR , p ) ;
return ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " process_name_release_request: Name release on name %s, \
1997-12-13 17:16:07 +03:00
subnet % s from owner IP % s \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( & nmb - > question . question_name ) ,
subrec - > subnet_name , inet_ntoa ( owner_ip ) ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/* If someone is releasing a broadcast group name, just ignore it. */
2007-10-11 05:25:16 +04:00
if ( group & & ! ismyip_v4 ( owner_ip ) )
2003-08-27 05:25:01 +04:00
return ;
/*
* Code to work around a bug in FTP OnNet software NBT implementation .
* They do a broadcast name release for WORKGROUP < 0 > and WORKGROUP < 1 e >
* names and * don ' t set the group bit * ! ! ! ! !
*/
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( qname , sizeof ( qname ) , question - > name ) ;
2007-10-11 05:25:16 +04:00
if ( ! group & & ! ismyip_v4 ( owner_ip ) & & strequal ( qname , lp_workgroup ( ) ) & &
2003-08-27 05:25:01 +04:00
( ( question - > name_type = = 0x0 ) | | ( question - > name_type = = 0x1e ) ) ) {
DEBUG ( 6 , ( " process_name_release_request: FTP OnNet bug workaround. Ignoring \
1998-02-26 22:26:18 +03:00
group release name % s from IP % s on subnet % s with no group bit set . \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( question ) , inet_ntoa ( owner_ip ) , subrec - > subnet_name ) ) ;
return ;
}
namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ;
/* We only care about someone trying to release one of our names. */
if ( namerec & & ( ( namerec - > data . source = = SELF_NAME )
| | ( namerec - > data . source = = PERMANENT_NAME ) ) ) {
rcode = ACT_ERR ;
DEBUG ( 0 , ( " process_name_release_request: Attempt to release name %s from IP %s \
1997-12-13 17:16:07 +03:00
on subnet % s being rejected as it is one of our names . \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( & nmb - > question . question_name ) , inet_ntoa ( owner_ip ) , subrec - > subnet_name ) ) ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
if ( rcode = = 0 )
return ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/* Send a NAME RELEASE RESPONSE (pos/neg) see rfc1002.txt 4.2.10-11 */
send_name_release_response ( rcode , p ) ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Send a name registration response .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void send_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 ] ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
memcpy ( & rdata [ 0 ] , & nmb - > additional - > rdata [ 0 ] , 6 ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
reply_netbios_packet ( p , /* Packet to reply to. */
rcode , /* Result code. */
NMB_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
}
/****************************************************************************
Process a name refresh request on a broadcast subnet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_name_refresh_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
struct in_addr from_ip ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
putip ( ( char * ) & from_ip , & nmb - > additional - > rdata [ 2 ] ) ;
if ( ! bcast ) {
/* We should only get broadcast name refresh packets here.
Anyone trying to refresh unicast should be going to a WINS
server . If the code gets here , then either we are not a wins
server and they sent it anyway , or we are a WINS server and
the request was malformed . Either way , log an error here .
and send an error reply back .
*/
DEBUG ( 0 , ( " process_name_refresh_request: unicast name registration request \
1999-12-13 16:27:58 +03:00
received for name % s from IP % s on subnet % s . \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) , subrec - > subnet_name ) ) ;
DEBUG ( 0 , ( " Error - should be sent to WINS server \n " ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
send_name_registration_response ( FMT_ERR , 0 , p ) ;
return ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/* Just log a message. We really don't care about broadcast name refreshes. */
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " process_name_refresh_request: Name refresh for name %s \
1998-11-14 04:04:13 +03:00
IP % s on subnet % s \ n " , nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Process a name registration request on a broadcast subnet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_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 ;
2015-04-30 06:14:34 +03:00
uint16_t 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 = nmb - > additional - > ttl ;
struct in_addr from_ip ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
putip ( ( char * ) & from_ip , & nmb - > additional - > rdata [ 2 ] ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
if ( ! bcast ) {
/* We should only get broadcast name registration packets here.
Anyone trying to register unicast should be going to a WINS
server . If the code gets here , then either we are not a wins
server and they sent it anyway , or we are a WINS server and
the request was malformed . Either way , log an error here .
and send an error reply back .
*/
DEBUG ( 0 , ( " process_name_registration_request: unicast name registration request \
1997-12-13 17:16:07 +03:00
received for name % s from IP % s on subnet % s . Error - should be sent to WINS server \ n " ,
2003-08-27 05:25:01 +04:00
nmb_namestr ( question ) , inet_ntoa ( from_ip ) , subrec - > subnet_name ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
send_name_registration_response ( FMT_ERR , 0 , p ) ;
return ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " process_name_registration_request: Name registration for name %s \
1998-11-14 04:04:13 +03:00
IP % s on subnet % s \ n " , nmb_namestr(question), inet_ntoa(from_ip), subrec->subnet_name));
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/* See if the name already exists. */
namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ;
1997-12-16 10:30:25 +03:00
2003-08-27 05:25:01 +04:00
/*
* If the name being registered exists and is a WINS_PROXY_NAME
* then delete the WINS proxy name entry so we don ' t reply erroneously
* later to queries .
*/
if ( ( namerec ! = NULL ) & & ( namerec - > data . source = = WINS_PROXY_NAME ) ) {
remove_name_from_namelist ( subrec , namerec ) ;
namerec = NULL ;
}
if ( ! group ) {
/* Unique name. */
if ( ( namerec ! = NULL )
& & ( ( namerec - > data . source = = SELF_NAME )
| | ( namerec - > data . source = = PERMANENT_NAME )
| | NAME_GROUP ( namerec ) ) ) {
/* No-one can register one of Samba's names, nor can they
register a name that ' s a group name as a unique name */
send_name_registration_response ( ACT_ERR , 0 , p ) ;
return ;
} else if ( namerec ! = NULL ) {
/* Update the namelist record with the new information. */
namerec - > data . ip [ 0 ] = from_ip ;
update_name_ttl ( namerec , ttl ) ;
DEBUG ( 3 , ( " process_name_registration_request: Updated name record %s \
1998-11-14 04:04:13 +03:00
with IP % s on subnet % s \ n " ,nmb_namestr(&namerec->name),inet_ntoa(from_ip), subrec->subnet_name));
2003-08-27 05:25:01 +04:00
return ;
}
} else {
/* Group name. */
if ( ( namerec ! = NULL )
& & ! NAME_GROUP ( namerec )
& & ( ( namerec - > data . source = = SELF_NAME )
| | ( namerec - > data . source = = PERMANENT_NAME ) ) ) {
/* Disallow group names when we have a unique name. */
send_name_registration_response ( ACT_ERR , 0 , p ) ;
return ;
}
}
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
This is used to sort names for a name status into a sensible order .
We put our own names first , then in alphabetical order .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int status_compare ( char * n1 , char * n2 )
{
2004-03-16 00:45:45 +03:00
unstring name1 , name2 ;
2003-08-27 05:25:01 +04:00
int l1 , l2 , l3 ;
2004-03-13 05:16:21 +03:00
memset ( name1 , ' \0 ' , sizeof ( name1 ) ) ;
memset ( name2 , ' \0 ' , sizeof ( name2 ) ) ;
pull_ascii_nstring ( name1 , sizeof ( name1 ) , n1 ) ;
pull_ascii_nstring ( name2 , sizeof ( name2 ) , n2 ) ;
2003-08-27 05:25:01 +04:00
n1 = name1 ;
n2 = name2 ;
/* It's a bit tricky because the names are space padded */
for ( l1 = 0 ; l1 < 15 & & n1 [ l1 ] & & n1 [ l1 ] ! = ' ' ; l1 + + )
;
for ( l2 = 0 ; l2 < 15 & & n2 [ l2 ] & & n2 [ l2 ] ! = ' ' ; l2 + + )
;
2011-06-09 09:31:03 +04:00
l3 = strlen ( lp_netbios_name ( ) ) ;
2003-08-27 05:25:01 +04:00
2011-06-09 09:31:03 +04:00
if ( ( l1 = = l3 ) & & strncmp ( n1 , lp_netbios_name ( ) , l3 ) = = 0 & &
( l2 ! = l3 | | strncmp ( n2 , lp_netbios_name ( ) , l3 ) ! = 0 ) )
2003-08-27 05:25:01 +04:00
return - 1 ;
2011-06-09 09:31:03 +04:00
if ( ( l2 = = l3 ) & & strncmp ( n2 , lp_netbios_name ( ) , l3 ) = = 0 & &
( l1 ! = l3 | | strncmp ( n1 , lp_netbios_name ( ) , l3 ) ! = 0 ) )
2003-08-27 05:25:01 +04:00
return 1 ;
2004-03-16 00:45:45 +03:00
return memcmp ( n1 , n2 , sizeof ( name1 ) ) ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Process a node status query
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_node_status_request ( struct subnet_record * subrec , struct packet_struct * p )
{
2003-08-27 05:25:01 +04:00
struct nmb_packet * nmb = & p - > packet . nmb ;
2004-03-16 00:45:45 +03:00
unstring qname ;
2003-08-27 05:25:01 +04:00
int ques_type = nmb - > question . question_name . name_type ;
char rdata [ MAX_DGRAM_SIZE ] ;
char * countptr , * buf , * bufend , * buf0 ;
int names_added , i ;
2009-01-20 02:09:51 +03:00
struct name_record * namerec = NULL ;
2003-08-27 05:25:01 +04:00
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( qname , sizeof ( qname ) , nmb - > question . question_name . name ) ;
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " process_node_status_request: status request for name %s from IP %s on \
subnet % s . \ n " , nmb_namestr(&nmb->question.question_name), inet_ntoa(p->ip), subrec->subnet_name));
2009-01-20 02:09:51 +03:00
if ( find_name_on_subnet ( subrec , & nmb - > question . question_name , FIND_SELF_NAME ) = = 0 ) {
2003-08-27 05:25:01 +04:00
DEBUG ( 1 , ( " process_node_status_request: status request for name %s from IP %s on \
1998-11-14 04:04:13 +03:00
subnet % s - name not found . \ n " , nmb_namestr(&nmb->question.question_name),
2003-08-27 05:25:01 +04:00
inet_ntoa ( p - > ip ) , subrec - > subnet_name ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
return ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/* this is not an exact calculation. the 46 is for the stats buffer
and the 60 is to leave room for the header etc */
2008-01-10 01:35:00 +03:00
bufend = & rdata [ MAX_DGRAM_SIZE - 1 ] - ( 18 + 46 + 60 ) ;
2003-08-27 05:25:01 +04:00
countptr = buf = rdata ;
buf + = 1 ;
buf0 = buf ;
names_added = 0 ;
2005-12-07 02:06:38 +03:00
namerec = subrec - > namelist ;
2003-08-27 05:25:01 +04:00
2018-04-05 23:28:12 +03:00
while ( PTR_DIFF ( bufend , buf ) > 0 ) {
2003-08-27 05:25:01 +04:00
if ( ( namerec - > data . source = = SELF_NAME ) | | ( namerec - > data . source = = PERMANENT_NAME ) ) {
int name_type = namerec - > name . name_type ;
2004-03-16 00:45:45 +03:00
unstring name ;
2003-08-27 05:25:01 +04:00
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( name , sizeof ( name ) , namerec - > name . name ) ;
2012-08-09 02:35:28 +04:00
if ( ! strupper_m ( name ) ) {
DEBUG ( 2 , ( " strupper_m %s failed \n " , name ) ) ;
return ;
}
2003-08-27 05:25:01 +04:00
if ( ! strequal ( name , " * " ) & &
! strequal ( name , " __SAMBA__ " ) & &
( name_type < 0x1b | | name_type > = 0x20 | |
ques_type < 0x1b | | ques_type > = 0x20 | |
strequal ( qname , name ) ) ) {
/* Start with the name. */
2004-03-13 05:16:21 +03:00
size_t len ;
push_ascii_nstring ( buf , name ) ;
len = strlen ( buf ) ;
memset ( buf + len , ' ' , MAX_NETBIOSNAME_LEN - len - 1 ) ;
buf [ MAX_NETBIOSNAME_LEN - 1 ] = ' \0 ' ;
2003-08-27 05:25:01 +04:00
/* Put the name type and netbios flags in the buffer. */
buf [ 15 ] = name_type ;
set_nb_flags ( & buf [ 16 ] , namerec - > data . nb_flags ) ;
buf [ 16 ] | = NB_ACTIVE ; /* all our names are active */
buf + = 18 ;
names_added + + ;
}
}
/* Remove duplicate names. */
if ( names_added > 1 ) {
2010-02-14 02:01:49 +03:00
/* TODO: should use a real type and
TYPESAFE_QSORT ( ) */
2003-08-27 05:25:01 +04:00
qsort ( buf0 , names_added , 18 , QSORT_CAST status_compare ) ;
}
for ( i = 1 ; i < names_added ; i + + ) {
if ( memcmp ( buf0 + 18 * i , buf0 + 18 * ( i - 1 ) , 16 ) = = 0 ) {
names_added - - ;
if ( names_added = = i )
break ;
memmove ( buf0 + 18 * i , buf0 + 18 * ( i + 1 ) , 18 * ( names_added - i ) ) ;
i - - ;
}
}
buf = buf0 + 18 * names_added ;
2005-12-07 02:06:38 +03:00
namerec = namerec - > next ;
2003-08-27 05:25:01 +04:00
if ( ! namerec ) {
/* End of the subnet specific name list. Now
add the names on the unicast subnet . */
struct subnet_record * uni_subrec = unicast_subnet ;
if ( uni_subrec ! = subrec ) {
subrec = uni_subrec ;
2005-12-07 02:06:38 +03:00
namerec = subrec - > namelist ;
2003-08-27 05:25:01 +04:00
}
}
if ( ! namerec )
break ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
SCVAL ( countptr , 0 , names_added ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/* We don't send any stats as they could be used to attack
the protocol . */
memset ( buf , ' \0 ' , 46 ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
buf + = 46 ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/* Send a NODE STATUS RESPONSE */
reply_netbios_packet ( p , /* Packet to reply to. */
0 , /* Result code. */
NMB_STATUS , /* nmbd type code. */
NMB_NAME_QUERY_OPCODE , /* opcode. */
0 , /* ttl. */
rdata , /* data to send. */
PTR_DIFF ( buf , rdata ) ) ; /* data length. */
1997-12-13 17:16:07 +03:00
}
/***************************************************************************
Process a name query .
For broadcast name queries :
- Only reply if the query is for one of YOUR names .
- NEVER send a negative response to a broadcast query .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_name_query_request ( struct subnet_record * subrec , struct packet_struct * p )
{
2002-07-15 14:35:28 +04:00
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
int name_type = question - > name_type ;
2007-10-19 04:40:25 +04:00
bool bcast = nmb - > header . nm_flags . bcast ;
2002-07-15 14:35:28 +04:00
int ttl = 0 ;
int rcode = 0 ;
char * prdata = NULL ;
char rdata [ 6 ] ;
2007-10-19 04:40:25 +04:00
bool success = False ;
2002-07-15 14:35:28 +04:00
struct name_record * namerec = NULL ;
int reply_data_len = 0 ;
int i ;
DEBUG ( 3 , ( " process_name_query_request: Name query from %s on subnet %s for name %s \n " ,
inet_ntoa ( p - > ip ) , subrec - > subnet_name , nmb_namestr ( question ) ) ) ;
1997-12-13 17:16:07 +03:00
2002-07-15 14:35:28 +04:00
/* Look up the name in the cache - if the request is a broadcast request that
came from a subnet we don ' t know about then search all the broadcast subnets
for a match ( as we don ' t know what interface the request came in on ) . */
if ( subrec = = remote_broadcast_subnet )
namerec = find_name_for_remote_broadcast_subnet ( question , FIND_ANY_NAME ) ;
else
namerec = find_name_on_subnet ( subrec , question , FIND_ANY_NAME ) ;
/* Check if it is a name that expired */
if ( namerec & &
( ( namerec - > data . death_time ! = PERMANENT_TTL ) & &
( namerec - > data . death_time < p - > timestamp ) ) ) {
DEBUG ( 5 , ( " process_name_query_request: expired name %s \n " , nmb_namestr ( & namerec - > name ) ) ) ;
namerec = NULL ;
}
if ( namerec ) {
/*
* Always respond to unicast queries .
* Don ' t respond to broadcast queries unless the query is for
* a name we own , a Primary Domain Controller name , or a WINS_PROXY
* name with type 0 or 0x20 . WINS_PROXY names are only ever added
* into the namelist if we were configured as a WINS proxy .
*/
if ( ! bcast | |
( bcast & & ( ( name_type = = 0x1b ) | |
( namerec - > data . source = = SELF_NAME ) | |
( namerec - > data . source = = PERMANENT_NAME ) | |
( ( namerec - > data . source = = WINS_PROXY_NAME ) & &
( ( name_type = = 0 ) | | ( name_type = = 0x20 ) ) ) ) ) ) {
/* The requested name is a directed query, or it's SELF or PERMANENT or WINS_PROXY,
or it ' s a Domain Master type . */
/*
* If this is a WINS_PROXY_NAME , then ceck that none of the IP
* addresses we are returning is on the same broadcast subnet
* as the requesting packet . If it is then don ' t reply as the
* actual machine will be replying also and we don ' t want two
* replies to a broadcast query .
*/
if ( namerec - > data . source = = WINS_PROXY_NAME ) {
for ( i = 0 ; i < namerec - > data . num_ips ; i + + ) {
2007-10-11 05:25:16 +04:00
if ( same_net_v4 ( namerec - > data . ip [ i ] , subrec - > myip , subrec - > mask_ip ) ) {
2002-07-15 14:35:28 +04:00
DEBUG ( 5 , ( " process_name_query_request: name %s is a WINS proxy name and is also on the same subnet (%s) as the requestor. Not replying. \n " ,
nmb_namestr ( & namerec - > name ) , subrec - > subnet_name ) ) ;
return ;
}
}
}
ttl = ( namerec - > data . death_time ! = PERMANENT_TTL ) ?
namerec - > data . death_time - p - > timestamp : lp_max_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 ) {
2002-07-15 14:35:28 +04:00
DEBUG ( 0 , ( " process_name_query_request: 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 ;
success = True ;
}
}
/*
* If a machine is broadcasting a name lookup request and we have lp_wins_proxy ( )
* set we should initiate a WINS query here . On success we add the resolved name
* into our namelist with a type of WINS_PROXY_NAME and then reply to the query .
*/
if ( ! success & & ( namerec = = NULL ) & & we_are_a_wins_client ( ) & & lp_wins_proxy ( ) & &
bcast & & ( subrec ! = remote_broadcast_subnet ) ) {
make_wins_proxy_name_query_request ( subrec , p , question ) ;
return ;
}
if ( ! success & & bcast ) {
if ( prdata ! = rdata )
SAFE_FREE ( prdata ) ;
return ; /* Never reply with a negative response to broadcasts. */
}
/*
* Final check . From observation , if a unicast packet is sent
* to a non - WINS server with the recursion desired bit set
* then never send a negative response .
*/
if ( ! success & & ! bcast & & nmb - > header . nm_flags . recursion_desired ) {
if ( prdata ! = rdata )
SAFE_FREE ( prdata ) ;
return ;
}
if ( success ) {
rcode = 0 ;
DEBUG ( 3 , ( " OK \n " ) ) ;
} else {
rcode = NAM_ERR ;
DEBUG ( 3 , ( " UNKNOWN \n " ) ) ;
}
/* See rfc1002.txt 4.2.13. */
reply_netbios_packet ( p , /* Packet to reply to. */
rcode , /* Result code. */
NMB_QUERY , /* nmbd type code. */
NMB_NAME_QUERY_OPCODE , /* opcode. */
ttl , /* ttl. */
prdata , /* data to send. */
reply_data_len ) ; /* data length. */
if ( prdata ! = rdata )
SAFE_FREE ( prdata ) ;
1997-12-13 17:16:07 +03:00
}