1996-07-07 17:29:56 +04:00
/*
Unix SMB / Netbios implementation .
Version 1.9 .
NBT netbios routines and daemon - version 2
Copyright ( C ) Andrew Tridgell 1994 - 1996
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 .
Module name : namedbname . c
Revision History :
14 jan 96 : lkcl @ pires . co . uk
added multiple workgroup domain master support
04 jul 96 : lkcl @ pires . co . uk
created module namedbname containing name database functions
*/
# include "includes.h"
extern int DEBUGLEVEL ;
extern pstring scope ;
extern struct in_addr ipzero ;
extern struct in_addr ipgrp ;
extern struct subnet_record * subnetlist ;
# define WINS_LIST "wins.dat"
1996-08-01 21:49:40 +04:00
uint16 nb_type = 0 ; /* samba's NetBIOS name type */
/****************************************************************************
samba ' s NetBIOS name type
XXXX maybe functionality could be set : B , M , P or H name registration
and resolution could be set through nb_type . just a thought .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void set_samba_nb_type ( void )
{
1996-10-02 19:41:30 +04:00
if ( lp_wins_support ( ) | | ( * lp_wins_server ( ) ) )
{
nb_type = NB_MFLAG ; /* samba is a 'hybrid' node type */
}
else
{
nb_type = NB_BFLAG ; /* samba is broadcast-only node type */
}
1996-08-01 21:49:40 +04:00
}
1996-07-07 17:29:56 +04:00
/****************************************************************************
true if two netbios names are equal
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL name_equal ( struct nmb_name * n1 , struct nmb_name * n2 )
{
return n1 - > name_type = = n2 - > name_type & &
1996-10-02 19:41:30 +04:00
strequal ( n1 - > name , n2 - > name ) & &
1996-07-07 17:29:56 +04:00
strequal ( n1 - > scope , n2 - > scope ) ;
}
/****************************************************************************
true if the netbios name is ^ 1 ^ 2 __MSBROWSE__ ^ 2 ^ 1
note : this name is registered if as a master browser or backup browser
you are responsible for a workgroup ( when you announce a domain by
broadcasting on your local subnet , you announce it as coming from this
name : see announce_host ( ) ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
BOOL ms_browser_name ( char * name , int type )
{
return strequal ( name , MSBROWSE ) & & type = = 0x01 ;
}
/****************************************************************************
add a netbios name into the namelist
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void add_name ( struct subnet_record * d , struct name_record * n )
{
struct name_record * n2 ;
if ( ! d ) return ;
if ( ! d - > namelist )
{
d - > namelist = n ;
n - > prev = NULL ;
n - > next = NULL ;
return ;
}
for ( n2 = d - > 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
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void remove_name ( struct subnet_record * d , struct name_record * n )
{
struct name_record * nlist ;
if ( ! d ) return ;
nlist = d - > namelist ;
while ( nlist & & nlist ! = n ) nlist = nlist - > next ;
if ( nlist )
{
if ( nlist - > next ) nlist - > next - > prev = nlist - > prev ;
if ( nlist - > prev ) nlist - > prev - > next = nlist - > next ;
free ( nlist ) ;
}
}
/****************************************************************************
find a name in a namelist .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct name_record * find_name ( struct name_record * n ,
1996-10-25 23:31:48 +04:00
struct nmb_name * name , int search )
1996-07-07 17:29:56 +04:00
{
1996-10-02 19:41:30 +04:00
struct name_record * ret ;
1996-07-07 17:29:56 +04:00
1996-10-02 19:41:30 +04:00
for ( ret = n ; ret ; ret = ret - > next )
{
if ( name_equal ( & ret - > name , name ) )
{
/* self search: self names only */
1996-10-27 17:22:56 +03:00
if ( ( search & FIND_SELF ) = = FIND_SELF & & ret - > source ! = SELF )
{
1996-10-02 19:41:30 +04:00
continue ;
1996-10-27 17:22:56 +03:00
}
1996-10-02 19:41:30 +04:00
return ret ;
}
}
1996-07-07 17:29:56 +04:00
return NULL ;
}
/****************************************************************************
find a name in the domain database namelist
search can be any of :
FIND_SELF - look exclusively for names the samba server has added for itself
FIND_LOCAL - look for names in the local subnet record .
FIND_WINS - look for names in the WINS record
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct name_record * find_name_search ( struct subnet_record * * d ,
1996-10-02 19:41:30 +04:00
struct nmb_name * name ,
int search , struct in_addr ip )
1996-07-07 17:29:56 +04:00
{
1996-10-02 19:41:30 +04:00
if ( d = = NULL ) return NULL ; /* bad error! */
if ( search & FIND_LOCAL ) {
if ( * d ! = NULL ) {
struct name_record * n = find_name ( ( * d ) - > namelist , name , search ) ;
DEBUG ( 4 , ( " find_name on local: %s %s search %x \n " ,
namestr ( name ) , inet_ntoa ( ip ) , search ) ) ;
if ( n ) return n ;
}
1996-08-21 12:30:29 +04:00
}
1996-10-02 19:41:30 +04:00
if ( ! ( search & FIND_WINS ) ) return NULL ;
1996-08-21 12:30:29 +04:00
/* find WINS subnet record. */
* d = find_subnet ( ipgrp ) ;
1996-10-02 19:41:30 +04:00
1996-08-21 12:30:29 +04:00
if ( * d = = NULL ) return NULL ;
1996-10-02 19:41:30 +04:00
1996-08-21 12:30:29 +04:00
DEBUG ( 4 , ( " find_name on WINS: %s %s search %x \n " ,
1996-10-02 19:41:30 +04:00
namestr ( name ) , inet_ntoa ( ip ) , search ) ) ;
1996-08-21 12:30:29 +04:00
return find_name ( ( * d ) - > namelist , name , search ) ;
1996-07-07 17:29:56 +04:00
}
/****************************************************************************
dump a copy of the name table
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void dump_names ( void )
{
struct name_record * n ;
struct subnet_record * d ;
fstring fname , fnamenew ;
time_t t = time ( NULL ) ;
FILE * f ;
strcpy ( fname , lp_lockdir ( ) ) ;
trim_string ( fname , NULL , " / " ) ;
strcat ( fname , " / " ) ;
strcat ( fname , WINS_LIST ) ;
strcpy ( fnamenew , fname ) ;
strcat ( fnamenew , " . " ) ;
f = fopen ( fnamenew , " w " ) ;
if ( ! f )
{
1996-11-06 23:27:50 +03:00
DEBUG ( 3 , ( " Can't open %s - %s \n " , fnamenew , strerror ( errno ) ) ) ;
1996-12-10 20:53:59 +03:00
return ;
1996-07-07 17:29:56 +04:00
}
1996-11-06 23:27:50 +03:00
DEBUG ( 4 , ( " Dump of local name table: \n " ) ) ;
1996-07-07 17:29:56 +04:00
for ( d = subnetlist ; d ; d = d - > next )
for ( n = d - > namelist ; n ; n = n - > next )
{
1996-08-17 17:17:45 +04:00
int i ;
1996-07-07 17:29:56 +04:00
1996-11-06 23:27:50 +03:00
DEBUG ( 4 , ( " %15s " , inet_ntoa ( d - > bcast_ip ) ) ) ;
DEBUG ( 4 , ( " %15s " , inet_ntoa ( d - > mask_ip ) ) ) ;
DEBUG ( 4 , ( " %-19s TTL=%ld " ,
1996-10-02 19:41:30 +04:00
namestr ( & n - > name ) ,
n - > death_time ? n - > death_time - t : 0 ) ) ;
1996-08-17 17:17:45 +04:00
for ( i = 0 ; i < n - > num_ips ; i + + )
{
1996-11-06 23:27:50 +03:00
DEBUG ( 4 , ( " %15s NB=%2x source=%d " ,
1996-10-02 19:41:30 +04:00
inet_ntoa ( n - > ip_flgs [ i ] . ip ) ,
n - > ip_flgs [ i ] . nb_flags , n - > source ) ) ;
1996-08-17 17:17:45 +04:00
}
1996-11-06 23:27:50 +03:00
DEBUG ( 4 , ( " \n " ) ) ;
1996-08-17 17:17:45 +04:00
if ( f & & ip_equal ( d - > bcast_ip , ipgrp ) & & n - > source = = REGISTER )
{
/* XXXX i have little imagination as to how to output nb_flags as
anything other than as a hexadecimal number : - ) */
1996-08-17 19:47:49 +04:00
fprintf ( f , " %s#%02x %ld " ,
1996-10-02 19:41:30 +04:00
n - > name . name , n - > name . name_type , /* XXXX ignore scope for now */
n - > death_time ) ;
1996-08-17 19:14:24 +04:00
1996-08-17 17:17:45 +04:00
for ( i = 0 ; i < n - > num_ips ; i + + )
{
1996-08-17 19:47:49 +04:00
fprintf ( f , " %s %2x " ,
1996-10-02 19:41:30 +04:00
inet_ntoa ( n - > ip_flgs [ i ] . ip ) ,
n - > ip_flgs [ i ] . nb_flags ) ;
1996-08-17 17:17:45 +04:00
}
1996-10-02 19:41:30 +04:00
fprintf ( f , " \n " ) ;
1996-08-17 17:17:45 +04:00
}
1996-08-17 19:14:24 +04:00
1996-07-07 17:29:56 +04:00
}
fclose ( f ) ;
unlink ( fname ) ;
chmod ( fnamenew , 0644 ) ;
rename ( fnamenew , fname ) ;
DEBUG ( 3 , ( " Wrote wins database %s \n " , fname ) ) ;
}
/****************************************************************************
1996-08-17 17:26:58 +04:00
load a netbios name database file
XXXX we cannot cope with loading Internet Group names , yet
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-07-07 17:29:56 +04:00
void load_netbios_names ( void )
{
struct subnet_record * d = find_subnet ( ipgrp ) ;
fstring fname ;
FILE * f ;
pstring line ;
if ( ! d ) return ;
strcpy ( fname , lp_lockdir ( ) ) ;
trim_string ( fname , NULL , " / " ) ;
strcat ( fname , " / " ) ;
strcat ( fname , WINS_LIST ) ;
f = fopen ( fname , " r " ) ;
if ( ! f ) {
DEBUG ( 2 , ( " Can't open wins database file %s \n " , fname ) ) ;
return ;
}
while ( ! feof ( f ) )
{
pstring name_str , ip_str , ttd_str , nb_flags_str ;
pstring name ;
int type = 0 ;
1996-08-17 19:14:24 +04:00
unsigned int nb_flags ;
1996-07-07 17:29:56 +04:00
time_t ttd ;
1996-10-02 19:41:30 +04:00
struct in_addr ipaddr ;
1996-08-17 19:14:24 +04:00
1996-10-02 19:41:30 +04:00
enum name_source source ;
1996-08-17 19:14:24 +04:00
1996-07-07 17:29:56 +04:00
char * ptr ;
1996-10-02 19:41:30 +04:00
int count = 0 ;
1996-08-17 19:14:24 +04:00
1996-07-07 17:29:56 +04:00
char * p ;
if ( ! fgets_slash ( line , sizeof ( pstring ) , f ) ) continue ;
if ( * line = = ' # ' ) continue ;
1996-10-02 19:41:30 +04:00
ptr = line ;
1996-08-17 17:17:45 +04:00
1996-10-02 19:41:30 +04:00
if ( next_token ( & ptr , name_str , NULL ) ) + + count ;
if ( next_token ( & ptr , ttd_str , NULL ) ) + + count ;
if ( next_token ( & ptr , ip_str , NULL ) ) + + count ;
if ( next_token ( & ptr , nb_flags_str , NULL ) ) + + count ;
1996-08-17 17:17:45 +04:00
1996-10-02 19:41:30 +04:00
if ( count < = 0 ) continue ;
1996-08-17 19:14:24 +04:00
1996-10-02 19:41:30 +04:00
if ( count ! = 4 ) {
DEBUG ( 0 , ( " Ill formed wins line " ) ) ;
DEBUG ( 0 , ( " [%s]: name#type abs_time ip nb_flags \n " , line ) ) ;
continue ;
}
1996-08-17 15:37:44 +04:00
1996-07-07 17:29:56 +04:00
/* netbios name. # divides the name from the type (hex): netbios#xx */
strcpy ( name , name_str ) ;
1996-08-17 17:17:45 +04:00
1996-07-07 17:29:56 +04:00
p = strchr ( name , ' # ' ) ;
if ( p ) {
1996-10-02 19:41:30 +04:00
* p = 0 ;
sscanf ( p + 1 , " %x " , & type ) ;
1996-07-07 17:29:56 +04:00
}
/* decode the netbios flags (hex) and the time-to-die (seconds) */
1996-10-02 19:41:30 +04:00
sscanf ( nb_flags_str , " %x " , & nb_flags ) ;
sscanf ( ttd_str , " %ld " , & ttd ) ;
1996-07-07 17:29:56 +04:00
1996-10-02 19:41:30 +04:00
ipaddr = * interpret_addr2 ( ip_str ) ;
1996-07-07 17:29:56 +04:00
if ( ip_equal ( ipaddr , ipzero ) ) {
source = SELF ;
}
else
{
source = REGISTER ;
}
1996-08-17 19:14:24 +04:00
DEBUG ( 4 , ( " add WINS line: %s#%02x %ld %s %2x \n " ,
1996-10-02 19:41:30 +04:00
name , type , ttd , inet_ntoa ( ipaddr ) , nb_flags ) ) ;
1996-07-07 17:29:56 +04:00
/* add all entries that have 60 seconds or more to live */
1996-08-17 19:14:24 +04:00
if ( ttd - 60 > time ( NULL ) | | ttd = = 0 )
1996-07-07 17:29:56 +04:00
{
time_t t = ( ttd ? ttd - time ( NULL ) : 0 ) / 3 ;
/* add netbios entry read from the wins.dat file. IF it's ok */
add_netbios_entry ( d , name , type , nb_flags , t , source , ipaddr , True , True ) ;
}
}
fclose ( f ) ;
}
/****************************************************************************
remove an entry from the name list
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void remove_netbios_name ( struct subnet_record * d ,
1996-10-02 19:41:30 +04:00
char * name , int type , enum name_source source ,
struct in_addr ip )
1996-07-07 17:29:56 +04:00
{
struct nmb_name nn ;
struct name_record * n ;
make_nmb_name ( & nn , name , type , scope ) ;
n = find_name_search ( & d , & nn , FIND_LOCAL , ip ) ;
if ( n & & n - > source = = source ) remove_name ( d , n ) ;
}
/****************************************************************************
add an entry to the name list .
this is a multi - purpose function .
it adds samba ' s own names in to its records on each interface , keeping a
record of whether it is a master browser , domain master , or WINS server .
it also keeps a record of WINS entries .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct name_record * add_netbios_entry ( struct subnet_record * d ,
1996-10-02 19:41:30 +04:00
char * name , int type , int nb_flags ,
int ttl , enum name_source source , struct in_addr ip ,
BOOL new_only , BOOL wins )
1996-07-07 17:29:56 +04:00
{
struct name_record * n ;
struct name_record * n2 = NULL ;
int search = 0 ;
1996-10-02 19:41:30 +04:00
BOOL self = source = = SELF ;
1996-07-07 17:29:56 +04:00
/* add the name to the WINS list if the name comes from a directed query */
search | = wins ? FIND_WINS : FIND_LOCAL ;
/* search for SELF names only */
search | = self ? FIND_SELF : 0 ;
if ( ! self )
{
if ( ! wins & & type ! = 0x1b )
{
/* the only broadcast (non-WINS) names we are adding are ours
1996-08-01 21:49:40 +04:00
( SELF ) and Domain Master type names */
1996-07-07 17:29:56 +04:00
return NULL ;
}
}
n = ( struct name_record * ) malloc ( sizeof ( * n ) ) ;
if ( ! n ) return ( NULL ) ;
bzero ( ( char * ) n , sizeof ( * n ) ) ;
1996-08-17 17:17:45 +04:00
n - > num_ips = 1 ; /* XXXX ONLY USE THIS FUNCTION FOR ONE ENTRY */
n - > ip_flgs = ( struct nmb_ip * ) malloc ( sizeof ( * n - > ip_flgs ) * n - > num_ips ) ;
if ( ! n - > ip_flgs )
{
free ( n ) ;
return NULL ;
}
1996-07-07 17:29:56 +04:00
make_nmb_name ( & n - > name , name , type , scope ) ;
if ( ( n2 = find_name_search ( & d , & n - > name , search , new_only ? ipzero : ip ) ) )
{
1996-08-17 17:17:45 +04:00
free ( n - > ip_flgs ) ;
1996-07-07 17:29:56 +04:00
free ( n ) ;
if ( new_only | | ( n2 - > source = = SELF & & source ! = SELF ) ) return n2 ;
n = n2 ;
}
if ( ttl )
n - > death_time = time ( NULL ) + ttl * 3 ;
n - > refresh_time = time ( NULL ) + GET_TTL ( ttl ) ;
1996-08-17 17:17:45 +04:00
/* XXXX only one entry expected with this function */
n - > ip_flgs [ 0 ] . ip = ip ;
n - > ip_flgs [ 0 ] . nb_flags = nb_flags ;
1996-07-07 17:29:56 +04:00
n - > source = source ;
if ( ! n2 ) add_name ( d , n ) ;
DEBUG ( 3 , ( " Added netbios name %s at %s ttl=%d nb_flags=%2x \n " ,
1996-10-02 19:41:30 +04:00
namestr ( & n - > name ) , inet_ntoa ( ip ) , ttl , nb_flags ) ) ;
1996-07-07 17:29:56 +04:00
return ( n ) ;
}
/*******************************************************************
1996-10-02 19:41:30 +04:00
expires old names in the namelist
1996-07-07 17:29:56 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-10-02 19:41:30 +04:00
void expire_names ( time_t t )
1996-07-07 17:29:56 +04:00
{
1996-10-02 19:41:30 +04:00
struct name_record * n ;
struct name_record * next ;
struct subnet_record * d ;
/* expire old names */
for ( d = subnetlist ; d ; d = d - > next )
{
for ( n = d - > namelist ; n ; n = next )
{
next = n - > next ;
if ( n - > death_time & & n - > death_time < t )
{
if ( n - > source = = SELF ) {
DEBUG ( 3 , ( " not expiring SELF name %s \n " , namestr ( & n - > name ) ) ) ;
n - > death_time + = 300 ;
continue ;
}
DEBUG ( 3 , ( " Removing dead name %s \n " , namestr ( & n - > name ) ) ) ;
if ( n - > prev ) n - > prev - > next = n - > next ;
if ( n - > next ) n - > next - > prev = n - > prev ;
if ( d - > namelist = = n ) d - > namelist = n - > next ;
free ( n - > ip_flgs ) ;
free ( n ) ;
}
}
}
1996-07-07 17:29:56 +04:00
}
/***************************************************************************
1996-10-25 23:31:48 +04:00
assume a WINS name is a dns name , and do a gethostbyname ( ) on it .
1996-07-07 17:29:56 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1996-10-25 23:31:48 +04:00
struct name_record * dns_name_search ( struct nmb_name * question , int Time )
1996-07-07 17:29:56 +04:00
{
1996-10-25 20:43:04 +04:00
int name_type = question - > name_type ;
char * qname = question - > name ;
1996-10-25 23:31:48 +04:00
char * r ;
1996-10-25 20:43:04 +04:00
BOOL dns_type = ( name_type = = 0x20 | | name_type = = 0 ) ;
struct in_addr dns_ip ;
struct subnet_record * d = find_subnet ( ipgrp ) ;
1996-10-24 21:48:06 +04:00
1996-10-25 20:43:04 +04:00
if ( d = = NULL ) return NULL ;
1996-10-24 04:09:08 +04:00
1996-10-25 20:43:04 +04:00
DEBUG ( 3 , ( " Search for %s - " , namestr ( question ) ) ) ;
/* only do DNS lookups if the query is for type 0x20 or type 0x0 */
1996-11-06 23:17:48 +03:00
if ( ! dns_type )
1996-10-02 19:41:30 +04:00
{
1996-11-06 23:17:48 +03:00
DEBUG ( 3 , ( " types 0x20 0x0 only: name not found \n " ) ) ;
1996-10-25 20:43:04 +04:00
return NULL ;
1996-10-02 19:41:30 +04:00
}
1996-10-25 20:43:04 +04:00
/* look it up with DNS */
1996-10-27 18:23:51 +03:00
dns_ip . s_addr = interpret_addr ( qname ) ;
1996-10-25 20:43:04 +04:00
if ( ! dns_ip . s_addr )
1996-10-02 19:41:30 +04:00
{
1996-10-25 20:43:04 +04:00
/* no luck with DNS. We could possibly recurse here XXXX */
DEBUG ( 3 , ( " not found. no recursion. \n " ) ) ;
/* add the fail to WINS cache of names. give it 1 hour in the cache */
add_netbios_entry ( d , qname , name_type , NB_ACTIVE , 60 * 60 , DNSFAIL , dns_ip ,
True , True ) ;
return NULL ;
1996-10-02 19:41:30 +04:00
}
1996-07-07 17:29:56 +04:00
1996-10-25 20:43:04 +04:00
DEBUG ( 3 , ( " found with DNS: %s \n " , inet_ntoa ( dns_ip ) ) ) ;
1996-07-07 17:29:56 +04:00
1996-10-25 20:43:04 +04:00
/* add it to our WINS cache of names. give it 2 hours in the cache */
return add_netbios_entry ( d , qname , name_type , NB_ACTIVE , 2 * 60 * 60 , DNS , dns_ip ,
True , True ) ;
}