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
Copyright ( C ) Jeremy Allison 1994 - 1998
1997-12-13 17:16:07 +03:00
This program is free software ; you can redistribute it and / or modify
it under the terms of the GNU General Public License as published by
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
*/
# include "includes.h"
2010-08-03 00:48:16 +04:00
# include "../librpc/gen_ndr/svcctl.h"
2010-08-18 17:22:09 +04:00
# include "nmbd/nmbd.h"
1997-12-13 17:16:07 +03:00
2015-04-30 06:14:34 +03:00
extern uint16_t samba_nb_type ;
1997-12-13 17:16:07 +03:00
int workgroup_count = 0 ; /* unique index key: one for each workgroup */
/****************************************************************************
Add a workgroup into the list .
2003-08-27 05:25:01 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-12-13 17:16:07 +03:00
static void add_workgroup ( struct subnet_record * subrec , struct work_record * work )
{
1999-12-13 16:27:58 +03:00
work - > subnet = subrec ;
DLIST_ADD ( subrec - > workgrouplist , work ) ;
subrec - > work_changed = True ;
1997-12-13 17:16:07 +03:00
}
2004-09-16 04:25:04 +04:00
/****************************************************************************
Copy name to unstring . Used by create_workgroup ( ) and find_workgroup_on_subnet ( ) .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void name_to_unstring ( unstring unname , const char * name )
{
nstring nname ;
errno = 0 ;
push_ascii_nstring ( nname , name ) ;
if ( errno = = E2BIG ) {
unstring tname ;
pull_ascii_nstring ( tname , sizeof ( tname ) , nname ) ;
2011-05-04 22:38:26 +04:00
strlcpy ( unname , tname , sizeof ( nname ) ) ;
2004-09-16 04:25:04 +04:00
DEBUG ( 0 , ( " name_to_nstring: workgroup name %s is too long. Truncating to %s \n " ,
name , tname ) ) ;
} else {
unstrcpy ( unname , name ) ;
}
}
1997-12-13 17:16:07 +03:00
/****************************************************************************
Create an empty workgroup .
2003-08-27 05:25:01 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-12-13 17:16:07 +03:00
2001-03-23 22:01:27 +03:00
static struct work_record * create_workgroup ( const char * name , int ttl )
1997-12-13 17:16:07 +03:00
{
2003-08-27 05:25:01 +04:00
struct work_record * work ;
struct subnet_record * subrec ;
int t = - 1 ;
1997-12-13 17:16:07 +03:00
2004-12-07 21:25:53 +03:00
if ( ( work = SMB_MALLOC_P ( struct work_record ) ) = = NULL ) {
2003-08-27 05:25:01 +04:00
DEBUG ( 0 , ( " create_workgroup: malloc fail ! \n " ) ) ;
return NULL ;
}
memset ( ( char * ) work , ' \0 ' , sizeof ( * work ) ) ;
2004-03-13 05:16:21 +03:00
2004-09-16 04:25:04 +04:00
name_to_unstring ( work - > work_group , name ) ;
2003-08-27 05:25:01 +04:00
work - > serverlist = NULL ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
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 ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
work - > death_time = ( ttl ! = PERMANENT_TTL ) ? time ( NULL ) + ( ttl * 3 ) : PERMANENT_TTL ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/* Make sure all token representations of workgroups are unique. */
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
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 ) {
2004-03-13 05:47:21 +03:00
if ( strequal ( w - > work_group , work - > work_group ) )
2003-08-27 05:25:01 +04:00
t = w - > token ;
}
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
if ( t = = - 1 )
work - > token = + + workgroup_count ;
else
work - > token = t ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/* 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 ' ;
2007-10-11 05:25:16 +04:00
zero_ip_v4 ( & work - > dmb_addr ) ;
2003-08-27 05:25:01 +04:00
/* WfWg uses 01040b01 */
/* Win95 uses 01041501 */
/* NTAS uses ???????? */
work - > ElectionCriterion = ( MAINTAIN_LIST ) | ( BROWSER_ELECTION_VERSION < < 8 ) ;
work - > ElectionCriterion | = ( lp_os_level ( ) < < 24 ) ;
if ( lp_domain_master ( ) )
work - > ElectionCriterion | = 0x80 ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
return work ;
1997-12-13 17:16:07 +03:00
}
/*******************************************************************
Remove a workgroup .
2003-08-27 05:25:01 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-12-13 17:16:07 +03:00
static struct work_record * remove_workgroup_from_subnet ( struct subnet_record * subrec ,
struct work_record * work )
{
2003-08-27 05:25:01 +04:00
struct work_record * ret_work = NULL ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " remove_workgroup: Removing workgroup %s \n " , work - > work_group ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
ret_work = work - > next ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
remove_all_servers ( work ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
if ( ! work - > serverlist ) {
2010-02-06 04:38:24 +03:00
DLIST_REMOVE ( subrec - > workgrouplist , work ) ;
2003-08-27 05:25:01 +04:00
ZERO_STRUCTP ( work ) ;
SAFE_FREE ( work ) ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
subrec - > work_changed = True ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
return ret_work ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Find a workgroup in the workgroup list of a subnet .
2003-08-27 05:25:01 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-12-13 17:16:07 +03:00
struct work_record * find_workgroup_on_subnet ( struct subnet_record * subrec ,
2000-04-24 15:30:45 +04:00
const char * name )
1997-12-13 17:16:07 +03:00
{
2003-08-27 05:25:01 +04:00
struct work_record * ret ;
2004-09-16 04:25:04 +04:00
unstring un_name ;
2003-08-27 05:25:01 +04:00
DEBUG ( 4 , ( " find_workgroup_on_subnet: workgroup search for %s on subnet %s: " ,
name , subrec - > subnet_name ) ) ;
1997-12-13 17:16:07 +03:00
2004-09-16 04:25:04 +04:00
name_to_unstring ( un_name , name ) ;
2003-08-27 05:25:01 +04:00
for ( ret = subrec - > workgrouplist ; ret ; ret = ret - > next ) {
2004-09-16 04:25:04 +04:00
if ( strequal ( ret - > work_group , un_name ) ) {
2003-08-27 05:25:01 +04:00
DEBUGADD ( 4 , ( " found. \n " ) ) ;
return ( ret ) ;
}
}
DEBUGADD ( 4 , ( " not found. \n " ) ) ;
return NULL ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Create a workgroup in the workgroup list of the subnet .
2003-08-27 05:25:01 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-12-13 17:16:07 +03:00
struct work_record * create_workgroup_on_subnet ( struct subnet_record * subrec ,
2001-03-23 22:01:27 +03:00
const char * name , int ttl )
1997-12-13 17:16:07 +03:00
{
2003-08-27 05:25:01 +04:00
struct work_record * work = NULL ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
DEBUG ( 4 , ( " create_workgroup_on_subnet: creating group %s on subnet %s \n " ,
name , subrec - > subnet_name ) ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
if ( ( work = create_workgroup ( name , ttl ) ) ) {
add_workgroup ( subrec , work ) ;
subrec - > work_changed = True ;
return ( work ) ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
return NULL ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Update a workgroup ttl .
2003-08-27 05:25:01 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-12-13 17:16:07 +03:00
void update_workgroup_ttl ( struct work_record * work , int ttl )
{
2003-08-27 05:25:01 +04:00
if ( work - > death_time ! = PERMANENT_TTL )
work - > death_time = time ( NULL ) + ( ttl * 3 ) ;
work - > subnet - > work_changed = True ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
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 )
{
2003-08-27 05:25:01 +04:00
DEBUG ( 0 , ( " fail_register: Failed to register name %s on subnet %s. \n " ,
nmb_namestr ( nmbname ) , subrec - > subnet_name ) ) ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
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 )
{
2003-08-27 05:25:01 +04:00
int i ;
1997-12-13 17:16:07 +03:00
2004-03-13 05:47:21 +03:00
if ( ! strequal ( lp_workgroup ( ) , work - > work_group ) )
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
/* If this is a broadcast subnet then start elections on it if we are so configured. */
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
if ( ( subrec ! = unicast_subnet ) & & ( subrec ! = remote_broadcast_subnet ) & &
( subrec ! = wins_server_subnet ) & & lp_preferred_master ( ) & & lp_local_master ( ) ) {
DEBUG ( 3 , ( " initiate_myworkgroup_startup: preferred master startup for \
1997-12-13 17:16:07 +03:00
workgroup % s on subnet % s \ n " , work->work_group, subrec->subnet_name));
2003-08-27 05:25:01 +04:00
work - > needelection = True ;
work - > ElectionCriterion | = ( 1 < < 3 ) ;
}
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
/* Register the WORKGROUP<0> and WORKGROUP<1e> names on the network. */
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
register_name ( subrec , lp_workgroup ( ) , 0x0 , samba_nb_type | NB_GROUP , NULL , fail_register , NULL ) ;
register_name ( subrec , lp_workgroup ( ) , 0x1e , samba_nb_type | NB_GROUP , NULL , fail_register , NULL ) ;
for ( i = 0 ; my_netbios_names ( i ) ; i + + ) {
const char * name = my_netbios_names ( i ) ;
int stype = lp_default_server_announce ( ) | ( lp_local_master ( ) ? SV_TYPE_POTENTIAL_BROWSER : 0 ) ;
1997-12-13 17:16:07 +03:00
2011-06-09 09:31:03 +04:00
if ( ! strequal ( lp_netbios_name ( ) , name ) )
2003-08-27 05:25:01 +04:00
stype & = ~ ( SV_TYPE_MASTER_BROWSER | SV_TYPE_POTENTIAL_BROWSER | SV_TYPE_DOMAIN_MASTER | SV_TYPE_DOMAIN_MEMBER ) ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
create_server_on_workgroup ( work , name , stype | SV_TYPE_LOCAL_LIST_ONLY , PERMANENT_TTL ,
2014-02-04 06:08:58 +04:00
string_truncate ( lp_server_string ( talloc_tos ( ) ) , MAX_SERVER_STRING_LENGTH ) ) ;
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " initiate_myworkgroup_startup: Added server name entry %s \
1997-12-13 17:16:07 +03:00
on subnet % s \ n " , name, subrec->subnet_name));
2003-08-27 05:25:01 +04:00
}
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Dump a copy of the workgroup database into the log file .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2007-10-19 04:40:25 +04:00
void dump_workgroups ( bool force_write )
1997-12-13 17:16:07 +03:00
{
2003-08-27 05:25:01 +04:00
struct subnet_record * subrec ;
int debuglevel = force_write ? 0 : 4 ;
1997-12-24 11:49:44 +03:00
2003-08-27 05:25:01 +04:00
for ( subrec = FIRST_SUBNET ; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST ( subrec ) ) {
if ( subrec - > workgrouplist ) {
struct work_record * work ;
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 ) ) ;
}
for ( work = subrec - > workgrouplist ; work ; work = work - > next ) {
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 " ) ) ;
if ( work - > serverlist ) {
struct server_record * servrec ;
for ( servrec = work - > serverlist ; servrec ; servrec = servrec - > next ) {
DEBUGADD ( debuglevel , ( " \t \t %s %8x (%s) \n " ,
servrec - > serv . name ,
servrec - > serv . type ,
servrec - > serv . comment ) ) ;
}
}
}
}
}
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Expire any dead servers on all workgroups . If the workgroup has expired
remove it .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void expire_workgroups_and_servers ( time_t t )
{
2003-08-27 05:25:01 +04:00
struct subnet_record * subrec ;
1997-12-13 17:16:07 +03:00
2003-08-27 05:25:01 +04:00
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 ) & &
2005-08-03 00:44:30 +04:00
( ( t = = ( time_t ) - 1 ) | | ( work - > death_time < t ) ) ) {
2003-08-27 05:25:01 +04:00
DEBUG ( 3 , ( " expire_workgroups_and_servers: Removing timed out workgroup %s \n " ,
work - > work_group ) ) ;
remove_workgroup_from_subnet ( subrec , work ) ;
}
}
}
1997-12-13 17:16:07 +03:00
}