1996-05-04 07:50:46 +00:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
NBT netbios routines and daemon - version 2
Copyright ( C ) Andrew Tridgell 1994 - 1995
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 .
1996-06-04 06:42:03 +00:00
Revision History :
14 jan 96 : lkcl @ pires . co . uk
added multiple workgroup domain master support
1996-05-04 07:50:46 +00:00
*/
# include "includes.h"
1996-06-06 11:43:09 +00:00
extern int ClientNMB ;
extern int ClientDGRAM ;
1996-05-04 07:50:46 +00:00
extern int DEBUGLEVEL ;
extern pstring scope ;
extern BOOL CanRecurse ;
1996-06-04 06:42:03 +00:00
extern pstring myname ;
extern struct in_addr ipzero ;
1996-06-08 05:37:33 +00:00
extern struct in_addr ipgrp ;
1996-05-04 07:50:46 +00:00
1996-06-04 06:42:03 +00:00
/* netbios names database */
struct name_record * namelist ;
1996-05-04 07:50:46 +00:00
# define GET_TTL(ttl) ((ttl)?MIN(ttl,lp_max_ttl()):lp_max_ttl())
/****************************************************************************
true if two netbios names are equal
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static BOOL name_equal ( struct nmb_name * n1 , struct nmb_name * n2 )
{
if ( n1 - > name_type ! = n2 - > name_type ) return ( False ) ;
return ( strequal ( n1 - > name , n2 - > name ) & & strequal ( n1 - > scope , n2 - > scope ) ) ;
}
/****************************************************************************
add a netbios name into the namelist
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void add_name ( struct name_record * n )
{
struct name_record * n2 ;
1996-06-04 06:42:03 +00:00
if ( ! namelist )
{
1996-05-04 07:50:46 +00:00
namelist = n ;
n - > prev = NULL ;
n - > next = NULL ;
return ;
}
for ( n2 = namelist ; n2 - > next ; n2 = n2 - > next ) ;
n2 - > next = n ;
n - > next = NULL ;
n - > prev = n2 ;
}
/****************************************************************************
remove a name from the namelist . The pointer must be an element just
retrieved
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 06:42:03 +00:00
void remove_name ( struct name_record * n )
1996-05-04 07:50:46 +00:00
{
struct name_record * nlist = namelist ;
1996-06-04 06:42:03 +00:00
1996-05-04 07:50:46 +00:00
while ( nlist & & nlist ! = n ) nlist = nlist - > next ;
1996-06-04 06:42:03 +00:00
if ( nlist )
{
1996-05-04 07:50:46 +00:00
if ( nlist - > next ) nlist - > next - > prev = nlist - > prev ;
if ( nlist - > prev ) nlist - > prev - > next = nlist - > next ;
free ( nlist ) ;
}
}
1996-06-08 05:37:33 +00:00
1996-05-04 07:50:46 +00:00
/****************************************************************************
1996-06-04 06:42:03 +00:00
find a name in the domain database namelist
search can be :
FIND_SELF - look for names the samba server has added for itself
FIND_GLOBAL - the name can be anyone . first look on the client ' s
subnet , then the server ' s subnet , then all subnets .
1996-05-04 07:50:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-08 05:37:33 +00:00
static struct name_record * find_name_search ( struct nmb_name * name ,
1996-06-06 11:43:09 +00:00
enum name_search search ,
1996-06-04 06:42:03 +00:00
struct in_addr ip )
1996-05-04 07:50:46 +00:00
{
1996-06-06 11:43:09 +00:00
struct name_record * ret ;
for ( ret = namelist ; ret ; ret = ret - > next )
{
1996-06-08 05:37:33 +00:00
if ( ! name_equal ( & ret - > name , name ) ) continue ;
if ( search = = FIND_SELF & & ret - > source ! = SELF ) continue ;
return ret ;
1996-06-06 11:43:09 +00:00
}
return NULL ;
1996-05-04 07:50:46 +00:00
}
1996-06-04 06:42:03 +00:00
1996-05-04 07:50:46 +00:00
/****************************************************************************
dump a copy of the name table
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 06:42:03 +00:00
void dump_names ( void )
1996-05-04 07:50:46 +00:00
{
1996-06-06 11:43:09 +00:00
struct name_record * n ;
time_t t = time ( NULL ) ;
DEBUG ( 3 , ( " Dump of local name table: \n " ) ) ;
for ( n = namelist ; n ; n = n - > next )
{
DEBUG ( 3 , ( " %s %s TTL=%d NBFLAGS=%2x \n " ,
namestr ( & n - > name ) ,
inet_ntoa ( n - > ip ) ,
n - > death_time ? n - > death_time - t : 0 ,
n - > nb_flags ) ) ;
}
1996-06-04 06:42:03 +00:00
}
1996-05-04 07:50:46 +00:00
1996-06-04 06:42:03 +00:00
/****************************************************************************
remove an entry from the name list
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void remove_netbios_name ( char * name , int type , enum name_source source ,
struct in_addr ip )
{
1996-06-06 11:43:09 +00:00
struct nmb_name nn ;
struct name_record * n ;
make_nmb_name ( & nn , name , type , scope ) ;
n = find_name_search ( & nn , FIND_GLOBAL , ip ) ;
if ( n & & n - > source = = source ) remove_name ( n ) ;
1996-05-04 07:50:46 +00:00
}
/****************************************************************************
1996-06-04 06:42:03 +00:00
add an entry to the name list
1996-05-04 07:50:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-06 11:43:09 +00:00
struct name_record * add_netbios_entry ( char * name , int type , int nb_flags ,
int ttl ,
enum name_source source ,
struct in_addr ip ,
BOOL new_only )
1996-05-04 07:50:46 +00:00
{
struct name_record * n ;
struct name_record * n2 = NULL ;
n = ( struct name_record * ) malloc ( sizeof ( * n ) ) ;
if ( ! n ) return ( NULL ) ;
bzero ( ( char * ) n , sizeof ( * n ) ) ;
make_nmb_name ( & n - > name , name , type , scope ) ;
1996-06-04 06:42:03 +00:00
1996-06-06 11:43:09 +00:00
if ( ( n2 = find_name_search ( & n - > name , FIND_GLOBAL , new_only ? ipzero : ip ) ) )
1996-06-04 06:42:03 +00:00
{
1996-05-04 07:50:46 +00:00
free ( n ) ;
1996-06-06 11:43:09 +00:00
if ( new_only | | ( n2 - > source = = SELF & & source ! = SELF ) ) return n2 ;
1996-05-04 07:50:46 +00:00
n = n2 ;
}
if ( ttl ) n - > death_time = time ( NULL ) + ttl * 3 ;
n - > ip = ip ;
1996-06-04 06:42:03 +00:00
n - > nb_flags = nb_flags ;
1996-05-04 07:50:46 +00:00
n - > source = source ;
if ( ! n2 ) add_name ( n ) ;
1996-06-04 06:42:03 +00:00
DEBUG ( 3 , ( " Added netbios name %s at %s ttl=%d nb_flags=%2x \n " ,
namestr ( & n - > name ) , inet_ntoa ( ip ) , ttl , nb_flags ) ) ;
1996-05-04 07:50:46 +00:00
return ( n ) ;
}
/****************************************************************************
1996-06-04 06:42:03 +00:00
remove an entry from the name list
1996-05-04 07:50:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 06:42:03 +00:00
void remove_name_entry ( char * name , int type )
1996-05-04 07:50:46 +00:00
{
1996-06-04 15:14:47 +00:00
if ( lp_wins_support ( ) )
{
/* we are a WINS server. */
1996-06-06 11:43:09 +00:00
remove_netbios_name ( name , type , SELF , ipzero ) ;
1996-06-04 15:14:47 +00:00
}
else
{
struct in_addr ip ;
ip = ipzero ;
queue_netbios_pkt_wins ( ClientNMB , NMB_REL , NAME_RELEASE ,
name , type , 0 ,
False , True , ip ) ;
}
1996-05-04 07:50:46 +00:00
}
1996-06-04 06:42:03 +00:00
1996-05-04 07:50:46 +00:00
/****************************************************************************
1996-06-04 06:42:03 +00:00
add an entry to the name list
1996-05-04 07:50:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 06:42:03 +00:00
void add_name_entry ( char * name , int type , int nb_flags )
1996-05-04 07:50:46 +00:00
{
1996-06-04 15:14:47 +00:00
/* always add our own entries */
1996-06-06 11:43:09 +00:00
add_netbios_entry ( name , type , nb_flags , 0 , SELF , ipzero , False ) ;
1996-06-04 15:14:47 +00:00
if ( ! lp_wins_support ( ) )
{
struct in_addr ip ;
ip = ipzero ;
queue_netbios_pkt_wins ( ClientNMB , NMB_REG , NAME_REGISTER ,
name , type , nb_flags ,
False , True , ip ) ;
}
1996-05-04 07:50:46 +00:00
}
/****************************************************************************
add the magic samba names , useful for finding samba servers
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 06:42:03 +00:00
void add_my_names ( void )
1996-05-04 07:50:46 +00:00
{
1996-06-04 15:14:47 +00:00
struct in_addr ip ;
1996-05-04 07:50:46 +00:00
1996-06-04 15:14:47 +00:00
ip = ipzero ;
add_name_entry ( myname , 0x20 , NB_ACTIVE ) ;
add_name_entry ( myname , 0x03 , NB_ACTIVE ) ;
add_name_entry ( myname , 0x00 , NB_ACTIVE ) ;
add_name_entry ( myname , 0x1f , NB_ACTIVE ) ;
1996-06-06 11:43:09 +00:00
add_netbios_entry ( " * " , 0x0 , NB_ACTIVE , 0 , SELF , ip , False ) ;
add_netbios_entry ( " __SAMBA__ " , 0x20 , NB_ACTIVE , 0 , SELF , ip , False ) ;
add_netbios_entry ( " __SAMBA__ " , 0x00 , NB_ACTIVE , 0 , SELF , ip , False ) ;
1996-06-07 03:34:22 +00:00
if ( lp_wins_support ( ) ) {
/* the 0x1c name gets added by any WINS server it seems */
add_name_entry ( my_workgroup ( ) , 0x1c , NB_ACTIVE | NB_GROUP ) ;
}
1996-05-04 07:50:46 +00:00
}
1996-06-08 05:37:33 +00:00
/****************************************************************************
remove all the samba names . . . from a WINS server if necessary .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void remove_my_names ( )
{
struct name_record * n ;
for ( n = namelist ; n ; n = n - > next )
{
if ( n - > source = = SELF )
{
/* get all SELF names removed from the WINS server's database */
remove_name_entry ( n - > name . name , n - > name . name_type ) ;
}
}
}
1996-05-04 07:50:46 +00:00
/*******************************************************************
1996-06-04 15:14:47 +00:00
refresh my own names
1996-05-04 07:50:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 15:14:47 +00:00
void refresh_my_names ( time_t t )
1996-05-04 07:50:46 +00:00
{
1996-06-04 15:14:47 +00:00
static time_t lasttime = 0 ;
1996-06-04 06:42:03 +00:00
1996-06-04 15:14:47 +00:00
if ( t - lasttime < REFRESH_TIME )
return ;
lasttime = t ;
1996-06-04 06:42:03 +00:00
1996-06-04 15:14:47 +00:00
add_my_names ( ) ;
}
1996-06-04 06:42:03 +00:00
1996-06-04 15:14:47 +00:00
/*******************************************************************
expires old names in the namelist
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void expire_names ( time_t t )
{
struct name_record * n ;
struct name_record * next ;
/* expire old names */
for ( n = namelist ; n ; n = next )
{
if ( n - > death_time & & n - > death_time < t )
{
DEBUG ( 3 , ( " Removing dead name %s \n " , namestr ( & n - > name ) ) ) ;
next = n - > next ;
if ( n - > prev ) n - > prev - > next = n - > next ;
if ( n - > next ) n - > next - > prev = n - > prev ;
if ( namelist = = n ) namelist = n - > next ;
free ( n ) ;
}
else
{
next = n - > next ;
}
}
1996-05-04 07:50:46 +00:00
}
1996-06-04 06:42:03 +00:00
/****************************************************************************
1996-06-08 05:37:33 +00:00
response for a reg release received
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 06:42:03 +00:00
void response_name_release ( struct packet_struct * p )
1996-05-04 07:50:46 +00:00
{
1996-06-04 15:14:47 +00:00
struct nmb_packet * nmb = & p - > packet . nmb ;
char * name = nmb - > question . question_name . name ;
int type = nmb - > question . question_name . name_type ;
DEBUG ( 4 , ( " response name release received \n " ) ) ;
if ( nmb - > header . rcode = = 0 & & nmb - > answers - > rdata )
{
struct in_addr found_ip ;
putip ( ( char * ) & found_ip , & nmb - > answers - > rdata [ 2 ] ) ;
1996-06-06 11:43:09 +00:00
if ( ismyip ( found_ip ) )
1996-06-04 15:14:47 +00:00
{
remove_netbios_name ( name , type , SELF , found_ip ) ;
}
}
else
{
DEBUG ( 1 , ( " name registration for %s rejected! \n " ,
namestr ( & nmb - > question . question_name ) ) ) ;
}
1996-05-04 07:50:46 +00:00
}
/****************************************************************************
1996-06-08 05:37:33 +00:00
reply to a name release
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 06:42:03 +00:00
void reply_name_release ( struct packet_struct * p )
1996-05-04 07:50:46 +00:00
{
1996-06-04 15:14:47 +00:00
struct nmb_packet * nmb = & p - > packet . nmb ;
struct in_addr ip ;
int rcode = 0 ;
int opcode = nmb - > header . opcode ;
int nb_flags = nmb - > additional - > rdata [ 0 ] ;
BOOL bcast = nmb - > header . nm_flags . bcast ;
struct name_record * n ;
char rdata [ 6 ] ;
putip ( ( char * ) & ip , & nmb - > additional - > rdata [ 2 ] ) ;
DEBUG ( 3 , ( " Name release on name %s rcode=%d \n " ,
1996-06-08 05:37:33 +00:00
namestr ( & nmb - > question . question_name ) , rcode ) ) ;
1996-06-04 15:14:47 +00:00
n = find_name_search ( & nmb - > question . question_name , FIND_GLOBAL , ip ) ;
/* XXXX under what conditions should we reject the removal?? */
1996-06-08 05:37:33 +00:00
if ( n & & n - > nb_flags = = nb_flags )
1996-06-04 15:14:47 +00:00
{
/* success = True;
rcode = 6 ; */
remove_name ( n ) ;
n = NULL ;
}
if ( bcast ) return ;
1996-06-08 05:37:33 +00:00
rdata [ 0 ] = nb_flags ;
rdata [ 1 ] = 0 ;
putip ( & rdata [ 2 ] , ( char * ) & ip ) ;
1996-06-04 15:14:47 +00:00
/* Send a NAME RELEASE RESPONSE */
1996-06-08 05:37:33 +00:00
reply_netbios_packet ( p , nmb - > header . name_trn_id ,
rcode , opcode , True ,
1996-06-04 15:14:47 +00:00
& nmb - > question . question_name ,
nmb - > question . question_type ,
nmb - > question . question_class ,
0 ,
1996-06-08 05:37:33 +00:00
rdata , 6 ) ;
1996-05-04 07:50:46 +00:00
}
/****************************************************************************
1996-06-08 05:37:33 +00:00
response for a reg request received
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 06:42:03 +00:00
void response_name_reg ( struct packet_struct * p )
1996-05-04 07:50:46 +00:00
{
1996-06-04 15:14:47 +00:00
struct nmb_packet * nmb = & p - > packet . nmb ;
char * name = nmb - > question . question_name . name ;
int type = nmb - > question . question_name . name_type ;
DEBUG ( 4 , ( " response name registration received! \n " ) ) ;
if ( nmb - > header . rcode = = 0 & & nmb - > answers - > rdata )
{
int nb_flags = nmb - > answers - > rdata [ 0 ] ;
struct in_addr found_ip ;
int ttl = nmb - > answers - > ttl ;
enum name_source source = REGISTER ;
putip ( ( char * ) & found_ip , & nmb - > answers - > rdata [ 2 ] ) ;
1996-06-06 11:43:09 +00:00
if ( ismyip ( found_ip ) ) source = SELF ;
1996-06-04 15:14:47 +00:00
1996-06-06 11:43:09 +00:00
add_netbios_entry ( name , type , nb_flags , ttl , source , found_ip , True ) ;
1996-06-04 15:14:47 +00:00
}
else
{
DEBUG ( 1 , ( " name registration for %s rejected! \n " ,
namestr ( & nmb - > question . question_name ) ) ) ;
}
1996-06-04 06:42:03 +00:00
}
1996-05-04 07:50:46 +00:00
1996-06-04 06:42:03 +00:00
/****************************************************************************
1996-06-08 05:37:33 +00:00
reply to a reg request
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 06:42:03 +00:00
void reply_name_reg ( struct packet_struct * p )
{
1996-06-04 15:14:47 +00:00
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
1996-06-08 05:37:33 +00:00
struct nmb_name * reply_name = question ;
char * qname = question - > name ;
int name_type = question - > name_type ;
int name_class = nmb - > question . question_class ;
1996-06-04 15:14:47 +00:00
BOOL bcast = nmb - > header . nm_flags . bcast ;
int ttl = GET_TTL ( nmb - > additional - > ttl ) ;
int nb_flags = nmb - > additional - > rdata [ 0 ] ;
1996-06-08 05:37:33 +00:00
BOOL group = NAME_GROUP ( nb_flags ) ;
1996-06-04 15:14:47 +00:00
int rcode = 0 ;
int opcode = nmb - > header . opcode ;
1996-06-08 05:37:33 +00:00
1996-06-04 15:14:47 +00:00
struct name_record * n = NULL ;
1996-06-08 05:37:33 +00:00
BOOL success = True ;
BOOL recurse = True ; /* true if samba replies yes/no: false if caller */
/* must challenge the current owner */
1996-06-04 15:14:47 +00:00
char rdata [ 6 ] ;
1996-06-08 05:37:33 +00:00
struct in_addr ip , from_ip ;
1996-06-04 15:14:47 +00:00
DEBUG ( 3 , ( " Name registration for name %s at %s rcode=%d \n " ,
namestr ( question ) , inet_ntoa ( ip ) , rcode ) ) ;
1996-06-08 05:37:33 +00:00
putip ( ( char * ) & from_ip , & nmb - > additional - > rdata [ 2 ] ) ;
ip = from_ip ;
1996-06-04 15:14:47 +00:00
if ( group )
{
/* apparently we should return 255.255.255.255 for group queries
( email from MS ) */
1996-06-08 05:37:33 +00:00
ip = ipgrp ;
1996-06-04 15:14:47 +00:00
}
/* see if the name already exists */
n = find_name_search ( question , FIND_GLOBAL , from_ip ) ;
if ( n )
{
1996-06-08 05:37:33 +00:00
if ( ! group ) /* unique names */
1996-06-04 15:14:47 +00:00
{
1996-06-08 05:37:33 +00:00
if ( n - > source = = SELF | | NAME_GROUP ( n - > nb_flags ) )
1996-06-04 15:14:47 +00:00
{
1996-06-08 05:37:33 +00:00
/* no-one can register one of samba's names, nor can they
register a name that ' s a group name as a unique name */
1996-06-04 15:14:47 +00:00
rcode = 6 ;
success = False ;
}
1996-06-08 05:37:33 +00:00
else if ( ! ip_equal ( ip , n - > ip ) )
{
/* hm. this unique name doesn't belong to them. */
/* XXXX rfc1001.txt says:
* if we are doing secured WINS , we must send a Wait - Acknowledge
* packet ( WACK ) to the person who wants the name , then do a
* name query on the person who currently owns the unique name .
* if the current owner is alive , the person who wants the name
* can ' t have it . if they are not alive , they can .
*
* if we are doing non - secure WINS ( which is much simpler ) then
* we send a message to the person wanting the name saying ' he
* owns this name : i don ' t want to hear from you ever again
* until you ' ve checked with him if you can have it ! ' . we then
* abandon the registration . once the person wanting the name
* has checked with the current owner , they will repeat the
* registration packet if the current owner is dead or doesn ' t
* want the name .
*/
/* non-secured WINS implementation: caller is responsible
for checking with current owner of name , then getting back
to us . . . IF current owner no longer owns the unique name */
rcode = 0 ;
success = False ;
recurse = False ;
/* we inform on the current owner to the caller (which is
why it ' s non - secure */
reply_name = & n - > name ;
/* name_type = ?;
name_class = ? ;
XXXX sorry , guys : i really can ' t see what name_type
and name_class should be set to according to rfc1001 */
}
1996-06-04 15:14:47 +00:00
else
{
1996-06-08 05:37:33 +00:00
/* XXXX removed code that checked with the owner of a name */
1996-06-04 15:14:47 +00:00
n - > ip = ip ;
n - > death_time = ttl ? p - > timestamp + ttl * 3 : 0 ;
1996-06-08 05:37:33 +00:00
DEBUG ( 3 , ( " %s owner: %s \n " , namestr ( & n - > name ) , inet_ntoa ( n - > ip ) ) ) ;
1996-06-04 15:14:47 +00:00
}
}
else
{
/* refresh the name */
if ( n - > source ! = SELF )
{
n - > death_time = ttl ? p - > timestamp + ttl * 3 : 0 ;
}
}
}
else
{
/* add the name to our subnet/name database */
1996-06-08 05:37:33 +00:00
n = add_netbios_entry ( qname , name_type , nb_flags , ttl , REGISTER , ip , True ) ;
1996-06-04 15:14:47 +00:00
}
if ( bcast ) return ;
1996-06-08 05:37:33 +00:00
if ( success )
{
update_from_reg ( nmb - > question . question_name . name ,
nmb - > question . question_name . name_type , from_ip ) ;
}
1996-06-04 15:14:47 +00:00
1996-06-08 05:37:33 +00:00
rdata [ 0 ] = nb_flags ;
rdata [ 1 ] = 0 ;
putip ( & rdata [ 2 ] , ( char * ) & ip ) ;
1996-06-04 15:14:47 +00:00
1996-06-08 05:37:33 +00:00
/* Send a NAME REGISTRATION RESPONSE (pos/neg)
or and END - NODE CHALLENGE REGISTRATION RESPONSE */
reply_netbios_packet ( p , nmb - > header . name_trn_id ,
rcode , opcode , recurse ,
reply_name , name_type , name_class ,
1996-06-04 15:14:47 +00:00
ttl ,
1996-06-08 05:37:33 +00:00
rdata , 6 ) ;
1996-05-04 07:50:46 +00:00
}
/****************************************************************************
1996-06-08 05:37:33 +00:00
reply to a name status query
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 06:42:03 +00:00
void reply_name_status ( struct packet_struct * p )
1996-05-04 07:50:46 +00:00
{
1996-06-04 15:14:47 +00:00
struct nmb_packet * nmb = & p - > packet . nmb ;
char * qname = nmb - > question . question_name . name ;
int ques_type = nmb - > question . question_name . name_type ;
char rdata [ MAX_DGRAM_SIZE ] ;
1996-06-08 05:37:33 +00:00
char * countptr , * buf , * bufend ;
int names_added ;
1996-06-04 15:14:47 +00:00
struct name_record * n ;
DEBUG ( 3 , ( " Name status for name %s %s \n " ,
1996-06-08 05:37:33 +00:00
namestr ( & nmb - > question . question_name ) , inet_ntoa ( p - > ip ) ) ) ;
1996-06-04 15:14:47 +00:00
1996-06-08 05:37:33 +00:00
n = find_name_search ( & nmb - > question . question_name , FIND_GLOBAL , p - > ip ) ;
1996-06-04 15:14:47 +00:00
1996-06-08 05:37:33 +00:00
if ( ! n ) return ;
1996-06-04 15:14:47 +00:00
/* XXXX hack, we should calculate exactly how many will fit */
1996-06-08 05:37:33 +00:00
bufend = & rdata [ MAX_DGRAM_SIZE ] - 18 ;
1996-06-04 15:14:47 +00:00
countptr = buf = rdata ;
buf + = 1 ;
names_added = 0 ;
1996-06-08 05:37:33 +00:00
for ( n = namelist ; n & & buf < bufend ; n = n - > next )
1996-06-04 15:14:47 +00:00
{
int name_type = n - > name . name_type ;
if ( n - > source ! = SELF ) continue ;
/* start with first bit of putting info in buffer: the name */
bzero ( buf , 18 ) ;
1996-06-08 05:37:33 +00:00
sprintf ( buf , " %-15.15s " , n - > name . name ) ;
1996-06-04 15:14:47 +00:00
strupper ( buf ) ;
/* now check if we want to exclude other workgroup names
from the response . if we don ' t exclude them , windows clients
get confused and will respond with an error for NET VIEW */
if ( name_type > = 0x1b & & name_type < = 0x20 & &
ques_type > = 0x1b & & ques_type < = 0x20 )
{
if ( ! strequal ( qname , n - > name . name ) ) continue ;
}
/* carry on putting name info in buffer */
buf [ 15 ] = name_type ;
buf [ 16 ] = n - > nb_flags ;
buf + = 18 ;
names_added + + ;
}
1996-06-08 05:37:33 +00:00
1996-06-04 15:14:47 +00:00
SCVAL ( countptr , 0 , names_added ) ;
/* XXXXXXX we should fill in more fields of the statistics structure */
bzero ( buf , 64 ) ;
{
extern int num_good_sends , num_good_receives ;
SIVAL ( buf , 20 , num_good_sends ) ;
SIVAL ( buf , 24 , num_good_receives ) ;
}
SIVAL ( buf , 46 , 0xFFB8E5 ) ; /* undocumented - used by NT */
buf + = 64 ;
/* Send a POSITIVE NAME STATUS RESPONSE */
1996-06-08 05:37:33 +00:00
reply_netbios_packet ( p , nmb - > header . name_trn_id ,
0 , 0 , True ,
1996-06-04 15:14:47 +00:00
& nmb - > question . question_name ,
nmb - > question . question_type ,
nmb - > question . question_class ,
0 ,
rdata , PTR_DIFF ( buf , rdata ) ) ;
1996-05-04 07:50:46 +00:00
}
1996-06-04 06:42:03 +00:00
/***************************************************************************
1996-06-08 05:37:33 +00:00
reply to a name query
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct name_record * search_for_name ( struct nmb_name * question ,
struct in_addr ip , int Time ,
enum name_search search )
1996-05-04 07:50:46 +00:00
{
1996-06-04 15:14:47 +00:00
int name_type = question - > name_type ;
char * qname = question - > name ;
BOOL dns_type = name_type = = 0x20 | | name_type = = 0 ;
struct name_record * n ;
DEBUG ( 3 , ( " Search for %s from %s - " , namestr ( question ) , inet_ntoa ( ip ) ) ) ;
1996-06-08 05:37:33 +00:00
/* first look up name in cache. use ip as well as name to locate it */
1996-06-04 15:14:47 +00:00
n = find_name_search ( question , search , ip ) ;
/* now try DNS lookup. */
if ( ! n )
{
struct in_addr dns_ip ;
unsigned long a ;
/* only do DNS lookups if the query is for type 0x20 or type 0x0 */
if ( ! dns_type )
{
DEBUG ( 3 , ( " types 0x20 0x1b 0x0 only: name not found \n " ) ) ;
return NULL ;
}
/* look it up with DNS */
a = interpret_addr ( qname ) ;
putip ( ( char * ) & dns_ip , ( char * ) & a ) ;
if ( ! a )
{
/* no luck with DNS. We could possibly recurse here XXXX */
/* if this isn't a bcast then we should send a negative reply XXXX */
DEBUG ( 3 , ( " no recursion \n " ) ) ;
1996-06-08 05:37:33 +00:00
add_netbios_entry ( qname , name_type , NB_ACTIVE , 60 * 60 , DNSFAIL , dns_ip , True ) ;
1996-06-04 15:14:47 +00:00
return NULL ;
}
/* add it to our cache of names. give it 2 hours in the cache */
1996-06-08 05:37:33 +00:00
n = add_netbios_entry ( qname , name_type , NB_ACTIVE , 2 * 60 * 60 , DNS , dns_ip , True ) ;
1996-06-04 15:14:47 +00:00
/* failed to add it? yikes! */
if ( ! n ) return NULL ;
}
/* is our entry already dead? */
if ( n - > death_time )
{
if ( n - > death_time < Time ) return False ;
}
/* it may have been an earlier failure */
if ( n - > source = = DNSFAIL )
{
DEBUG ( 3 , ( " DNSFAIL \n " ) ) ;
return NULL ;
}
DEBUG ( 3 , ( " OK %s \n " , inet_ntoa ( n - > ip ) ) ) ;
return n ;
1996-06-04 06:42:03 +00:00
}
1996-05-04 07:50:46 +00:00
1996-06-08 05:37:33 +00:00
/***************************************************************************
reply to a name query
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void reply_name_query ( struct packet_struct * p )
1996-05-04 07:50:46 +00:00
{
1996-06-04 15:14:47 +00:00
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
int name_type = question - > name_type ;
1996-06-08 05:37:33 +00:00
BOOL dns_type = name_type = = 0x20 | | name_type = = 0 ;
1996-06-04 15:14:47 +00:00
BOOL bcast = nmb - > header . nm_flags . bcast ;
int ttl = 0 ;
int rcode = 0 ;
int nb_flags = 0 ;
struct in_addr retip ;
char rdata [ 6 ] ;
BOOL success = True ;
struct name_record * n ;
1996-06-08 05:37:33 +00:00
enum name_search search = ( dns_type | | name_type = = 0x1b ) ?
1996-06-04 15:14:47 +00:00
FIND_GLOBAL : FIND_SELF ;
1996-06-06 11:43:09 +00:00
1996-06-04 15:14:47 +00:00
DEBUG ( 3 , ( " Name query " ) ) ;
if ( ( n = search_for_name ( question , p - > ip , p - > timestamp , search ) ) )
{
/* don't respond to broadcast queries unless the query is for
a name we own or it is for a Primary Domain Controller name */
if ( bcast & & n - > source ! = SELF & & name_type ! = 0x1b )
{
1996-06-06 11:43:09 +00:00
if ( ! lp_wins_proxy ( ) | | same_net ( p - > ip , n - > ip , * iface_nmask ( p - > ip ) ) ) {
1996-06-04 15:14:47 +00:00
/* never reply with a negative response to broadcast queries */
return ;
}
}
1996-06-08 05:37:33 +00:00
/* name is directed query, or it's self, or it's a PDC type name */
1996-06-04 15:14:47 +00:00
ttl = n - > death_time - p - > timestamp ;
retip = n - > ip ;
nb_flags = n - > nb_flags ;
}
else
{
if ( bcast ) return ; /* never reply negative response to bcasts */
success = False ;
}
1996-06-06 11:43:09 +00:00
/* if the IP is 0 then substitute my IP */
if ( zero_ip ( retip ) ) retip = * iface_ip ( p - > ip ) ;
1996-06-08 05:37:33 +00:00
1996-06-04 15:14:47 +00:00
if ( success )
{
rcode = 0 ;
DEBUG ( 3 , ( " OK %s \n " , inet_ntoa ( retip ) ) ) ;
}
else
{
rcode = 3 ;
DEBUG ( 3 , ( " UNKNOWN \n " ) ) ;
}
if ( success )
{
rdata [ 0 ] = nb_flags ;
rdata [ 1 ] = 0 ;
putip ( & rdata [ 2 ] , ( char * ) & retip ) ;
}
1996-06-08 05:37:33 +00:00
reply_netbios_packet ( p , nmb - > header . name_trn_id ,
rcode , 0 , True ,
1996-06-04 15:14:47 +00:00
& nmb - > question . question_name ,
nmb - > question . question_type ,
nmb - > question . question_class ,
ttl ,
rdata , success ? 6 : 0 ) ;
1996-05-04 07:50:46 +00:00
}
1996-06-08 05:37:33 +00:00
1996-05-04 07:50:46 +00:00
/****************************************************************************
1996-06-04 06:42:03 +00:00
response from a name query
1996-05-04 07:50:46 +00:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-06-04 06:42:03 +00:00
static void response_netbios_packet ( struct packet_struct * p )
1996-05-04 07:50:46 +00:00
{
1996-06-04 15:14:47 +00:00
struct nmb_packet * nmb = & p - > packet . nmb ;
struct nmb_name * question = & nmb - > question . question_name ;
char * qname = question - > name ;
BOOL bcast = nmb - > header . nm_flags . bcast ;
struct name_response_record * n ;
if ( nmb - > answers = = NULL )
{
DEBUG ( 3 , ( " NMB packet response from %s (bcast=%s) - UNKNOWN \n " ,
inet_ntoa ( p - > ip ) ,
BOOLSTR ( bcast ) ) ) ;
return ;
}
if ( nmb - > answers - > rr_type = = NMB_STATUS ) {
DEBUG ( 3 , ( " Name status " ) ) ;
}
1996-06-04 06:42:03 +00:00
1996-06-04 15:14:47 +00:00
if ( nmb - > answers - > rr_type = = NMB_QUERY ) {
DEBUG ( 3 , ( " Name query " ) ) ;
}
1996-06-04 06:42:03 +00:00
1996-06-04 15:14:47 +00:00
if ( nmb - > answers - > rr_type = = NMB_REG ) {
DEBUG ( 3 , ( " Name registration " ) ) ;
}
1996-06-04 06:42:03 +00:00
1996-06-04 15:14:47 +00:00
if ( nmb - > answers - > rr_type = = NMB_REL ) {
DEBUG ( 3 , ( " Name release " ) ) ;
}
1996-06-04 06:42:03 +00:00
1996-06-04 15:14:47 +00:00
DEBUG ( 3 , ( " response for %s from %s (bcast=%s) \n " ,
namestr ( & nmb - > answers - > rr_name ) ,
inet_ntoa ( p - > ip ) ,
BOOLSTR ( bcast ) ) ) ;
if ( ! ( n = find_name_query ( nmb - > header . name_trn_id ) ) ) {
DEBUG ( 3 , ( " unknown response (received too late or from nmblookup?) \n " ) ) ;
return ;
}
1996-06-04 06:42:03 +00:00
1996-06-04 15:14:47 +00:00
n - > num_msgs + + ; /* count number of responses received */
switch ( n - > cmd_type )
{
case MASTER_SERVER_CHECK : DEBUG ( 4 , ( " MASTER_SVR_CHECK \n " ) ) ; break ;
case SERVER_CHECK : DEBUG ( 4 , ( " SERVER_CHECK \n " ) ) ; break ;
case FIND_MASTER : DEBUG ( 4 , ( " FIND_MASTER \n " ) ) ; break ;
case NAME_STATUS_MASTER_CHECK : DEBUG ( 4 , ( " NAME_STAT_MST_CHK \n " ) ) ; break ;
case NAME_STATUS_CHECK : DEBUG ( 4 , ( " NAME_STATUS_CHECK \n " ) ) ; break ;
case CHECK_MASTER : DEBUG ( 4 , ( " CHECK_MASTER \n " ) ) ; break ;
case NAME_CONFIRM_QUERY : DEBUG ( 4 , ( " NAME_CONFIRM_QUERY \n " ) ) ; break ;
default : break ;
}
switch ( n - > cmd_type )
{
case MASTER_SERVER_CHECK :
case SERVER_CHECK :
case FIND_MASTER :
{
if ( nmb - > answers - > rr_type = = NMB_QUERY )
{
enum cmd_type cmd = ( n - > cmd_type = = MASTER_SERVER_CHECK ) ?
NAME_STATUS_MASTER_CHECK :
NAME_STATUS_CHECK ;
if ( n - > num_msgs > 1 & & ! strequal ( qname , n - > name . name ) )
{
/* one subnet, one master browser per workgroup */
/* XXXX force an election? */
DEBUG ( 1 , ( " more than one master browser replied! \n " ) ) ;
}
/* initiate a name status check on the server that replied */
queue_netbios_packet ( ClientNMB , NMB_STATUS , cmd ,
nmb - > answers - > rr_name . name ,
nmb - > answers - > rr_name . name_type , 0 ,
False , False , n - > to_ip ) ;
}
else
{
DEBUG ( 1 , ( " Name query reply has wrong answer rr_type \n " ) ) ;
}
break ;
}
case NAME_STATUS_MASTER_CHECK :
case NAME_STATUS_CHECK :
{
if ( nmb - > answers - > rr_type = = NMB_STATUS )
{
/* NMB_STATUS arrives: contains the workgroup name
and server name we require */
struct nmb_name name ;
fstring serv_name ;
if ( interpret_node_status ( nmb - > answers - > rdata ,
1996-06-06 11:43:09 +00:00
& name , 0x1d , serv_name , p - > ip ) )
1996-06-04 15:14:47 +00:00
{
if ( * serv_name )
{
sync_server ( n - > cmd_type , serv_name ,
name . name , name . name_type ,
n - > to_ip ) ;
}
}
else
{
DEBUG ( 1 , ( " No 0x1d name type in interpret_node_status() \n " ) ) ;
}
}
else
{
DEBUG ( 1 , ( " Name status reply has wrong answer rr_type \n " ) ) ;
}
break ;
}
case CHECK_MASTER :
{
/* no action required here. it's when NO responses are received
that we need to do something ( see expire_name_query_entries ) */
DEBUG ( 4 , ( " Master browser exists for %s at %s \n " ,
namestr ( & n - > name ) ,
inet_ntoa ( n - > to_ip ) ) ) ;
if ( n - > num_msgs > 1 )
{
DEBUG ( 1 , ( " more than one master browser! \n " ) ) ;
}
if ( nmb - > answers - > rr_type ! = NMB_QUERY )
{
DEBUG ( 1 , ( " Name query reply has wrong answer rr_type \n " ) ) ;
}
break ;
}
case NAME_CONFIRM_QUERY :
{
DEBUG ( 4 , ( " Name query at WINS server: %s at %s - " ,
namestr ( & n - > name ) ,
inet_ntoa ( n - > to_ip ) ) ) ;
if ( nmb - > header . rcode = = 0 & & nmb - > answers - > rdata )
{
int nb_flags = nmb - > answers - > rdata [ 0 ] ;
struct in_addr found_ip ;
putip ( ( char * ) & found_ip , & nmb - > answers - > rdata [ 2 ] ) ;
DEBUG ( 4 , ( " OK: %s \n " , inet_ntoa ( found_ip ) ) ) ;
add_netbios_entry ( nmb - > answers - > rr_name . name ,
nmb - > answers - > rr_name . name_type ,
1996-06-06 11:43:09 +00:00
nb_flags , GET_TTL ( 0 ) , STATUS_QUERY , found_ip , False ) ;
1996-06-04 15:14:47 +00:00
}
else
{
DEBUG ( 4 , ( " NEGATIVE RESPONSE \n " ) ) ;
}
break ;
}
default :
{
DEBUG ( 0 , ( " unknown command received in response_netbios_packet \n " ) ) ;
break ;
}
}
1996-05-04 07:50:46 +00:00
}
/****************************************************************************
1996-06-04 06:42:03 +00:00
process a nmb packet
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void process_nmb ( struct packet_struct * p )
1996-05-04 07:50:46 +00:00
{
1996-06-06 11:43:09 +00:00
struct nmb_packet * nmb = & p - > packet . nmb ;
1996-05-04 07:50:46 +00:00
1996-06-06 11:43:09 +00:00
debug_nmb_packet ( p ) ;
1996-05-04 07:50:46 +00:00
1996-06-06 11:43:09 +00:00
switch ( nmb - > header . opcode )
{
case 5 :
case 8 :
case 9 :
{
if ( nmb - > header . qdcount = = 0 | | nmb - > header . arcount = = 0 ) break ;
if ( nmb - > header . response )
response_name_reg ( p ) ;
else
reply_name_reg ( p ) ;
break ;
}
case 0 :
{
if ( nmb - > header . response )
{
switch ( nmb - > question . question_type )
{
case 0x0 :
1996-06-04 06:42:03 +00:00
{
1996-06-06 11:43:09 +00:00
response_netbios_packet ( p ) ;
break ;
1996-06-04 06:42:03 +00:00
}
1996-06-06 11:43:09 +00:00
}
return ;
}
else if ( nmb - > header . qdcount > 0 )
{
switch ( nmb - > question . question_type )
{
case NMB_QUERY :
1996-06-04 06:42:03 +00:00
{
1996-06-06 11:43:09 +00:00
reply_name_query ( p ) ;
break ;
1996-06-04 06:42:03 +00:00
}
1996-06-06 11:43:09 +00:00
case NMB_STATUS :
1996-06-04 06:42:03 +00:00
{
1996-06-06 11:43:09 +00:00
reply_name_status ( p ) ;
break ;
1996-06-04 06:42:03 +00:00
}
1996-06-06 11:43:09 +00:00
}
return ;
}
break ;
}
case 6 :
{
if ( nmb - > header . qdcount = = 0 | | nmb - > header . arcount = = 0 )
{
DEBUG ( 2 , ( " netbios release packet rejected \n " ) ) ;
break ;
}
if ( nmb - > header . response )
response_name_release ( p ) ;
else
reply_name_release ( p ) ;
break ;
}
}
1996-05-04 07:50:46 +00:00
}