0001-01-01 02:30:17 +02:30
/*
0001-01-01 02:30:17 +02:30
Unix SMB / CIFS implementation .
0001-01-01 02:30:17 +02:30
NBT netbios routines and daemon - version 2
0001-01-01 02:30:17 +02:30
Copyright ( C ) Andrew Tridgell 1994 - 1998
Copyright ( C ) Luke Kenneth Casson Leighton 1994 - 1998
Copyright ( C ) Jeremy Allison 1994 - 1998
0001-01-01 02:30:17 +02:30
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"
# include "smb.h"
extern int ClientNMB ;
0001-01-01 02:30:17 +02:30
extern pstring global_myname ;
extern fstring global_myworkgroup ;
0001-01-01 02:30:17 +02:30
extern char * * my_netbios_names ;
extern uint16 samba_nb_type ;
int workgroup_count = 0 ; /* unique index key: one for each workgroup */
/****************************************************************************
Add a workgroup into the list .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void add_workgroup ( struct subnet_record * subrec , struct work_record * work )
{
0001-01-01 02:30:17 +02:30
work - > subnet = subrec ;
DLIST_ADD ( subrec - > workgrouplist , work ) ;
subrec - > work_changed = True ;
0001-01-01 02:30:17 +02:30
}
/****************************************************************************
Create an empty workgroup .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
static struct work_record * create_workgroup ( const char * name , int ttl )
0001-01-01 02:30:17 +02:30
{
struct work_record * work ;
struct subnet_record * subrec ;
int t = - 1 ;
if ( ( work = ( struct work_record * ) malloc ( sizeof ( * work ) ) ) = = NULL )
{
DEBUG ( 0 , ( " create_workgroup: malloc fail ! \n " ) ) ;
return NULL ;
}
0001-01-01 02:30:17 +02:30
memset ( ( char * ) work , ' \0 ' , sizeof ( * work ) ) ;
0001-01-01 02:30:17 +02:30
StrnCpy ( work - > work_group , name , sizeof ( work - > work_group ) - 1 ) ;
work - > serverlist = NULL ;
work - > RunningElection = False ;
work - > ElectionCount = 0 ;
work - > announce_interval = 0 ;
work - > needelection = False ;
work - > needannounce = True ;
work - > lastannounce_time = time ( NULL ) ;
work - > mst_state = lp_local_master ( ) ? MST_POTENTIAL : MST_NONE ;
work - > dom_state = DOMAIN_NONE ;
work - > log_state = LOGON_NONE ;
work - > death_time = ( ttl ! = PERMANENT_TTL ) ? time ( NULL ) + ( ttl * 3 ) : PERMANENT_TTL ;
/* Make sure all token representations of workgroups are unique. */
for ( subrec = FIRST_SUBNET ; subrec & & ( t = = - 1 ) ;
subrec = NEXT_SUBNET_INCLUDING_UNICAST ( subrec ) )
{
struct work_record * w ;
for ( w = subrec - > workgrouplist ; w & & t = = - 1 ; w = w - > next )
{
if ( strequal ( w - > work_group , work - > work_group ) )
t = w - > token ;
}
}
if ( t = = - 1 )
work - > token = + + workgroup_count ;
else
work - > token = t ;
/* No known local master browser as yet. */
* work - > local_master_browser_name = ' \0 ' ;
/* No known domain master browser as yet. */
* work - > dmb_name . name = ' \0 ' ;
0001-01-01 02:30:17 +02:30
zero_ip ( & work - > dmb_addr ) ;
0001-01-01 02:30:17 +02:30
/* WfWg uses 01040b01 */
/* Win95 uses 01041501 */
/* NTAS uses ???????? */
0001-01-01 02:30:17 +02:30
work - > ElectionCriterion = ( MAINTAIN_LIST ) | ( BROWSER_ELECTION_VERSION < < 8 ) ;
0001-01-01 02:30:17 +02:30
work - > ElectionCriterion | = ( lp_os_level ( ) < < 24 ) ;
if ( lp_domain_master ( ) )
work - > ElectionCriterion | = 0x80 ;
return work ;
}
/*******************************************************************
Remove a workgroup .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static struct work_record * remove_workgroup_from_subnet ( struct subnet_record * subrec ,
struct work_record * work )
{
struct work_record * ret_work = NULL ;
DEBUG ( 3 , ( " remove_workgroup: Removing workgroup %s \n " , work - > work_group ) ) ;
ret_work = work - > next ;
remove_all_servers ( work ) ;
if ( ! work - > serverlist )
{
if ( work - > prev )
work - > prev - > next = work - > next ;
if ( work - > next )
work - > next - > prev = work - > prev ;
if ( subrec - > workgrouplist = = work )
subrec - > workgrouplist = work - > next ;
0001-01-01 02:30:17 +02:30
ZERO_STRUCTP ( work ) ;
0001-01-01 02:30:17 +02:30
SAFE_FREE ( work ) ;
0001-01-01 02:30:17 +02:30
}
subrec - > work_changed = True ;
return ret_work ;
}
/****************************************************************************
Find a workgroup in the workgroup list of a subnet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct work_record * find_workgroup_on_subnet ( struct subnet_record * subrec ,
0001-01-01 02:30:17 +02:30
const char * name )
0001-01-01 02:30:17 +02:30
{
struct work_record * ret ;
DEBUG ( 4 , ( " find_workgroup_on_subnet: workgroup search for %s on subnet %s: " ,
name , subrec - > subnet_name ) ) ;
for ( ret = subrec - > workgrouplist ; ret ; ret = ret - > next )
{
if ( ! strcmp ( ret - > work_group , name ) )
{
0001-01-01 02:30:17 +02:30
DEBUGADD ( 4 , ( " found. \n " ) ) ;
0001-01-01 02:30:17 +02:30
return ( ret ) ;
}
}
0001-01-01 02:30:17 +02:30
DEBUGADD ( 4 , ( " not found. \n " ) ) ;
0001-01-01 02:30:17 +02:30
return NULL ;
}
/****************************************************************************
Create a workgroup in the workgroup list of the subnet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct work_record * create_workgroup_on_subnet ( struct subnet_record * subrec ,
0001-01-01 02:30:17 +02:30
const char * name , int ttl )
0001-01-01 02:30:17 +02:30
{
struct work_record * work = NULL ;
DEBUG ( 4 , ( " create_workgroup_on_subnet: creating group %s on subnet %s \n " ,
name , subrec - > subnet_name ) ) ;
if ( ( work = create_workgroup ( name , ttl ) ) )
{
add_workgroup ( subrec , work ) ;
subrec - > work_changed = True ;
return ( work ) ;
}
return NULL ;
}
/****************************************************************************
Update a workgroup ttl .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void update_workgroup_ttl ( struct work_record * work , int ttl )
{
if ( work - > death_time ! = PERMANENT_TTL )
work - > death_time = time ( NULL ) + ( ttl * 3 ) ;
work - > subnet - > work_changed = True ;
}
/****************************************************************************
Fail function called if we cannot register the WORKGROUP < 0 > and
WORKGROUP < 1 e > names on the net .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void fail_register ( struct subnet_record * subrec , struct response_record * rrec ,
struct nmb_name * nmbname )
{
DEBUG ( 0 , ( " fail_register: Failed to register name %s on subnet %s. \n " ,
0001-01-01 02:30:17 +02:30
nmb_namestr ( nmbname ) , subrec - > subnet_name ) ) ;
0001-01-01 02:30:17 +02:30
}
/****************************************************************************
If the workgroup is our primary workgroup , add the required names to it .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void initiate_myworkgroup_startup ( struct subnet_record * subrec , struct work_record * work )
{
int i ;
0001-01-01 02:30:17 +02:30
if ( ! strequal ( global_myworkgroup , work - > work_group ) )
0001-01-01 02:30:17 +02:30
return ;
/* If this is a broadcast subnet then start elections on it
if we are so configured . */
if ( ( subrec ! = unicast_subnet ) & & ( subrec ! = remote_broadcast_subnet ) & &
0001-01-01 02:30:17 +02:30
( subrec ! = wins_server_subnet ) & & lp_preferred_master ( ) & &
lp_local_master ( ) )
0001-01-01 02:30:17 +02:30
{
DEBUG ( 3 , ( " initiate_myworkgroup_startup: preferred master startup for \
workgroup % s on subnet % s \ n " , work->work_group, subrec->subnet_name));
work - > needelection = True ;
work - > ElectionCriterion | = ( 1 < < 3 ) ;
}
/* Register the WORKGROUP<0> and WORKGROUP<1e> names on the network. */
0001-01-01 02:30:17 +02:30
register_name ( subrec , global_myworkgroup , 0x0 , samba_nb_type | NB_GROUP ,
0001-01-01 02:30:17 +02:30
NULL ,
fail_register , NULL ) ;
0001-01-01 02:30:17 +02:30
register_name ( subrec , global_myworkgroup , 0x1e , samba_nb_type | NB_GROUP ,
0001-01-01 02:30:17 +02:30
NULL ,
fail_register , NULL ) ;
for ( i = 0 ; my_netbios_names [ i ] ; i + + )
{
char * name = my_netbios_names [ i ] ;
int stype = lp_default_server_announce ( ) | ( lp_local_master ( ) ?
SV_TYPE_POTENTIAL_BROWSER : 0 ) ;
0001-01-01 02:30:17 +02:30
if ( ! strequal ( global_myname , name ) )
0001-01-01 02:30:17 +02:30
stype & = ~ ( SV_TYPE_MASTER_BROWSER | SV_TYPE_POTENTIAL_BROWSER |
SV_TYPE_DOMAIN_MASTER | SV_TYPE_DOMAIN_MEMBER ) ;
create_server_on_workgroup ( work , name , stype | SV_TYPE_LOCAL_LIST_ONLY ,
0001-01-01 02:30:17 +02:30
PERMANENT_TTL ,
string_truncate ( lp_serverstring ( ) , MAX_SERVER_STRING_LENGTH ) ) ;
0001-01-01 02:30:17 +02:30
DEBUG ( 3 , ( " initiate_myworkgroup_startup: Added server name entry %s \
on subnet % s \ n " , name, subrec->subnet_name));
}
}
/****************************************************************************
Dump a copy of the workgroup database into the log file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
0001-01-01 02:30:17 +02:30
void dump_workgroups ( BOOL force_write )
0001-01-01 02:30:17 +02:30
{
struct subnet_record * subrec ;
0001-01-01 02:30:17 +02:30
int debuglevel = force_write ? 0 : 4 ;
0001-01-01 02:30:17 +02:30
for ( subrec = FIRST_SUBNET ; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST ( subrec ) )
{
if ( subrec - > workgrouplist )
{
struct work_record * work ;
0001-01-01 02:30:17 +02:30
if ( DEBUGLVL ( debuglevel ) )
{
dbgtext ( " dump_workgroups() \n " ) ;
dbgtext ( " dump workgroup on subnet %15s: " , subrec - > subnet_name ) ;
dbgtext ( " netmask=%15s: \n " , inet_ntoa ( subrec - > mask_ip ) ) ;
}
0001-01-01 02:30:17 +02:30
for ( work = subrec - > workgrouplist ; work ; work = work - > next )
{
0001-01-01 02:30:17 +02:30
DEBUGADD ( debuglevel , ( " \t %s(%d) current master browser = %s \n " ,
work - > work_group ,
work - > token ,
* work - > local_master_browser_name
? work - > local_master_browser_name : " UNKNOWN " ) ) ;
0001-01-01 02:30:17 +02:30
if ( work - > serverlist )
{
struct server_record * servrec ;
for ( servrec = work - > serverlist ; servrec ; servrec = servrec - > next )
{
0001-01-01 02:30:17 +02:30
DEBUGADD ( debuglevel , ( " \t \t %s %8x (%s) \n " ,
servrec - > serv . name ,
servrec - > serv . type ,
servrec - > serv . comment ) ) ;
0001-01-01 02:30:17 +02:30
}
}
}
}
}
}
/****************************************************************************
Expire any dead servers on all workgroups . If the workgroup has expired
remove it .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void expire_workgroups_and_servers ( time_t t )
{
struct subnet_record * subrec ;
for ( subrec = FIRST_SUBNET ; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST ( subrec ) )
{
struct work_record * work ;
struct work_record * nextwork ;
for ( work = subrec - > workgrouplist ; work ; work = nextwork )
{
nextwork = work - > next ;
expire_servers ( work , t ) ;
if ( ( work - > serverlist = = NULL ) & & ( work - > death_time ! = PERMANENT_TTL ) & &
( ( t = = - 1 ) | | ( work - > death_time < t ) ) )
{
DEBUG ( 3 , ( " expire_workgroups_and_servers: Removing timed out workgroup %s \n " ,
work - > work_group ) ) ;
remove_workgroup_from_subnet ( subrec , work ) ;
}
}
}
}