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-23 05:59:14 +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
*/
# 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
extern uint16 samba_nb_type ; /* Samba's NetBIOS type. */
2002-11-13 02:20:50 +03:00
static void become_domain_master_browser_bcast ( const char * ) ;
1997-12-13 17:16:07 +03:00
/****************************************************************************
Fail to become a Domain Master Browser on a subnet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void become_domain_master_fail ( struct subnet_record * subrec ,
struct response_record * rrec ,
struct nmb_name * fail_name )
{
2004-03-16 00:45:45 +03:00
unstring failname ;
2003-08-23 05:59:14 +04:00
struct work_record * work ;
struct server_record * servrec ;
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( failname , sizeof ( failname ) , fail_name - > name ) ;
2003-08-23 05:59:14 +04:00
work = find_workgroup_on_subnet ( subrec , failname ) ;
if ( ! work ) {
DEBUG ( 0 , ( " become_domain_master_fail: Error - cannot find \
workgroup % s on subnet % s \ n " , failname, subrec->subnet_name));
return ;
}
/* Set the state back to DOMAIN_NONE. */
work - > dom_state = DOMAIN_NONE ;
if ( ( servrec = find_server_in_workgroup ( work , global_myname ( ) ) ) = = NULL ) {
DEBUG ( 0 , ( " become_domain_master_fail: Error - cannot find server %s \
1997-12-13 17:16:07 +03:00
in workgroup % s on subnet % s \ n " ,
2003-08-23 05:59:14 +04:00
global_myname ( ) , work - > work_group , subrec - > subnet_name ) ) ;
return ;
}
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* Update our server status. */
servrec - > serv . type & = ~ SV_TYPE_DOMAIN_MASTER ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* Tell the namelist writer to write out a change. */
subrec - > work_changed = True ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
DEBUG ( 0 , ( " become_domain_master_fail: Failed to become a domain master browser for \
1997-12-13 17:16:07 +03:00
workgroup % s on subnet % s . Couldn ' t register name % s . \ n " ,
2003-08-23 05:59:14 +04:00
work - > work_group , subrec - > subnet_name , nmb_namestr ( fail_name ) ) ) ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Become a Domain Master Browser on a subnet .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void become_domain_master_stage2 ( struct subnet_record * subrec ,
struct userdata_struct * userdata ,
struct nmb_name * registered_name ,
uint16 nb_flags ,
int ttl , struct in_addr registered_ip )
{
2004-03-16 00:45:45 +03:00
unstring regname ;
2003-08-23 05:59:14 +04:00
struct work_record * work ;
struct server_record * servrec ;
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( regname , sizeof ( regname ) , registered_name - > name ) ;
2003-08-23 05:59:14 +04:00
work = find_workgroup_on_subnet ( subrec , regname ) ;
if ( ! work ) {
DEBUG ( 0 , ( " become_domain_master_stage2: Error - cannot find \
workgroup % s on subnet % s \ n " , regname, subrec->subnet_name));
return ;
}
if ( ( servrec = find_server_in_workgroup ( work , global_myname ( ) ) ) = = NULL ) {
DEBUG ( 0 , ( " become_domain_master_stage2: Error - cannot find server %s \
1997-12-13 17:16:07 +03:00
in workgroup % s on subnet % s \ n " ,
2003-08-23 05:59:14 +04:00
global_myname ( ) , regname , subrec - > subnet_name ) ) ;
work - > dom_state = DOMAIN_NONE ;
return ;
}
/* Set the state in the workgroup structure. */
work - > dom_state = DOMAIN_MST ; /* Become domain master. */
/* Update our server status. */
servrec - > serv . type | = ( SV_TYPE_NT | SV_TYPE_DOMAIN_MASTER ) ;
/* Tell the namelist writer to write out a change. */
subrec - > work_changed = True ;
if ( DEBUGLVL ( 0 ) ) {
dbgtext ( " ***** \n \n Samba server %s " , global_myname ( ) ) ;
dbgtext ( " is now a domain master browser for " ) ;
dbgtext ( " workgroup %s " , work - > work_group ) ;
dbgtext ( " on subnet %s \n \n ***** \n " , subrec - > subnet_name ) ;
}
if ( subrec = = unicast_subnet ) {
struct nmb_name nmbname ;
struct in_addr my_first_ip ;
2007-10-11 05:25:16 +04:00
const struct in_addr * nip ;
2003-08-23 05:59:14 +04:00
/* Put our name and first IP address into the
workgroup struct as domain master browser . This
will stop us syncing with ourself if we are also
a local master browser . */
make_nmb_name ( & nmbname , global_myname ( ) , 0x20 ) ;
work - > dmb_name = nmbname ;
2006-06-14 04:37:52 +04:00
2009-02-05 03:05:36 +03:00
/* Pick the first interface IPv4 address as the domain master
* browser ip . */
2007-10-11 05:25:16 +04:00
nip = first_ipv4_iface ( ) ;
2006-06-14 04:37:52 +04:00
if ( ! nip ) {
2007-10-11 05:25:16 +04:00
DEBUG ( 0 , ( " become_domain_master_stage2: "
" Error. get_interface returned NULL \n " ) ) ;
2006-06-14 04:37:52 +04:00
return ;
}
my_first_ip = * nip ;
2003-08-23 05:59:14 +04:00
putip ( ( char * ) & work - > dmb_addr , & my_first_ip ) ;
/* We successfully registered by unicast with the
WINS server . We now expect to become the domain
master on the local subnets . If this fails , it ' s
probably a 1.9 .16 p2 to 1.9 .16 p11 server ' s fault .
This is a configuration issue that should be addressed
by the network administrator - you shouldn ' t have
several machines configured as a domain master browser
for the same WINS scope ( except if they are 1.9 .17 or
greater , and you know what you ' re doing .
see docs / DOMAIN . txt .
*/
become_domain_master_browser_bcast ( work - > work_group ) ;
} else {
/*
* Now we are a domain master on a broadcast subnet , we need to add
* the WORKGROUP < 1 b > name to the unicast subnet so that we can answer
* unicast requests sent to this name . This bug wasn ' t found for a while
* as it is strange to have a DMB without using WINS . JRA .
*/
insert_permanent_name_into_unicast ( subrec , registered_name , nb_flags ) ;
}
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Start the name registration process when becoming a Domain Master Browser
on a subnet .
2003-08-23 05:59:14 +04:00
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
static void become_domain_master_stage1 ( struct subnet_record * subrec , const char * wg_name )
1997-12-13 17:16:07 +03:00
{
2003-08-23 05:59:14 +04:00
struct work_record * work ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
DEBUG ( 2 , ( " become_domain_master_stage1: Becoming domain master browser for \
1997-12-13 17:16:07 +03:00
workgroup % s on subnet % s \ n " , wg_name, subrec->subnet_name));
2003-08-23 05:59:14 +04:00
/* First, find the workgroup on the subnet. */
if ( ( work = find_workgroup_on_subnet ( subrec , wg_name ) ) = = NULL ) {
DEBUG ( 0 , ( " become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s. \n " ,
wg_name , subrec - > subnet_name ) ) ;
return ;
}
DEBUG ( 3 , ( " become_domain_master_stage1: go to first stage: register <1b> name \n " ) ) ;
work - > dom_state = DOMAIN_WAIT ;
/* WORKGROUP<1b> is the domain master browser name. */
register_name ( subrec , work - > work_group , 0x1b , samba_nb_type ,
become_domain_master_stage2 ,
become_domain_master_fail , NULL ) ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Function called when a query for a WORKGROUP < 1 b > name succeeds .
This is normally a fail condition as it means there is already
a domain master browser for a workgroup and we were trying to
become one .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void become_domain_master_query_success ( struct subnet_record * subrec ,
struct userdata_struct * userdata ,
2007-10-11 05:25:16 +04:00
struct nmb_name * nmbname , struct in_addr ip ,
1997-12-13 17:16:07 +03:00
struct res_rec * rrec )
{
2004-03-16 00:45:45 +03:00
unstring name ;
2007-10-11 05:25:16 +04:00
struct in_addr allones_ip ;
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( name , sizeof ( name ) , nmbname - > name ) ;
2003-08-23 05:59:14 +04:00
/* If the given ip is not ours, then we can't become a domain
controler as the name is already registered .
*/
/* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
address or zero ip for this query . Pretend this is ok . */
2007-10-11 05:25:16 +04:00
allones_ip . s_addr = htonl ( INADDR_BROADCAST ) ;
2007-10-25 01:16:54 +04:00
if ( ismyip_v4 ( ip ) | | ip_equal_v4 ( allones_ip , ip ) | | is_zero_ip_v4 ( ip ) ) {
2003-08-23 05:59:14 +04:00
if ( DEBUGLVL ( 3 ) ) {
dbgtext ( " become_domain_master_query_success(): \n " ) ;
dbgtext ( " Our address (%s) " , inet_ntoa ( ip ) ) ;
dbgtext ( " returned in query for name %s " , nmb_namestr ( nmbname ) ) ;
dbgtext ( " (domain master browser name) " ) ;
dbgtext ( " on subnet %s. \n " , subrec - > subnet_name ) ;
dbgtext ( " Continuing with domain master code. \n " ) ;
}
become_domain_master_stage1 ( subrec , name ) ;
} else {
if ( DEBUGLVL ( 0 ) ) {
dbgtext ( " become_domain_master_query_success: \n " ) ;
dbgtext ( " There is already a domain master browser at " ) ;
dbgtext ( " IP %s for workgroup %s " , inet_ntoa ( ip ) , name ) ;
dbgtext ( " registered on subnet %s. \n " , subrec - > subnet_name ) ;
}
}
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Function called when a query for a WORKGROUP < 1 b > name fails .
This is normally a success condition as it then allows us to register
our own Domain Master Browser name .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void become_domain_master_query_fail ( struct subnet_record * subrec ,
struct response_record * rrec ,
struct nmb_name * question_name , int fail_code )
{
2004-03-16 00:45:45 +03:00
unstring name ;
2003-08-23 05:59:14 +04:00
/* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
then this is a failure . Otherwise , not finding the name is what we want . */
if ( ( subrec = = unicast_subnet ) & & ( fail_code ! = NAM_ERR ) ) {
DEBUG ( 0 , ( " become_domain_master_query_fail: Error %d returned when \
1997-12-13 17:16:07 +03:00
querying WINS server for name % s . \ n " ,
2003-08-23 05:59:14 +04:00
fail_code , nmb_namestr ( question_name ) ) ) ;
return ;
}
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* Otherwise - not having the name allows us to register it. */
2004-03-13 05:16:21 +03:00
pull_ascii_nstring ( name , sizeof ( name ) , question_name - > name ) ;
2003-08-23 05:59:14 +04:00
become_domain_master_stage1 ( subrec , name ) ;
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Attempt to become a domain master browser on all broadcast subnets .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-11-13 02:20:50 +03:00
static void become_domain_master_browser_bcast ( const char * workgroup_name )
1997-12-13 17:16:07 +03:00
{
2003-08-23 05:59:14 +04:00
struct subnet_record * subrec ;
for ( subrec = FIRST_SUBNET ; subrec ; subrec = NEXT_SUBNET_EXCLUDING_UNICAST ( subrec ) ) {
struct work_record * work = find_workgroup_on_subnet ( subrec , workgroup_name ) ;
if ( work & & ( work - > dom_state = = DOMAIN_NONE ) ) {
struct nmb_name nmbname ;
make_nmb_name ( & nmbname , workgroup_name , 0x1b ) ;
/*
* Check for our name on the given broadcast subnet first , only initiate
* further processing if we cannot find it .
*/
if ( find_name_on_subnet ( subrec , & nmbname , FIND_SELF_NAME ) = = NULL ) {
if ( DEBUGLVL ( 0 ) ) {
dbgtext ( " become_domain_master_browser_bcast: \n " ) ;
dbgtext ( " Attempting to become domain master browser on " ) ;
dbgtext ( " workgroup %s on subnet %s \n " ,
workgroup_name , subrec - > subnet_name ) ;
}
/* Send out a query to establish whether there's a
domain controller on the local subnet . If not ,
we can become a domain controller .
*/
DEBUG ( 0 , ( " become_domain_master_browser_bcast: querying subnet %s \
1997-12-13 17:16:07 +03:00
for domain master browser on workgroup % s \ n " , subrec->subnet_name, workgroup_name));
2003-08-23 05:59:14 +04:00
query_name ( subrec , workgroup_name , nmbname . name_type ,
become_domain_master_query_success ,
become_domain_master_query_fail ,
NULL ) ;
}
}
}
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Attempt to become a domain master browser by registering with WINS .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2002-11-13 02:20:50 +03:00
static void become_domain_master_browser_wins ( const char * workgroup_name )
1997-12-13 17:16:07 +03:00
{
2003-08-23 05:59:14 +04:00
struct work_record * work ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
work = find_workgroup_on_subnet ( unicast_subnet , workgroup_name ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
if ( work & & ( work - > dom_state = = DOMAIN_NONE ) ) {
struct nmb_name nmbname ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
make_nmb_name ( & nmbname , workgroup_name , 0x1b ) ;
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/*
* Check for our name on the unicast subnet first , only initiate
* further processing if we cannot find it .
*/
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
if ( find_name_on_subnet ( unicast_subnet , & nmbname , FIND_SELF_NAME ) = = NULL ) {
if ( DEBUGLVL ( 0 ) ) {
dbgtext ( " become_domain_master_browser_wins: \n " ) ;
dbgtext ( " Attempting to become domain master browser " ) ;
dbgtext ( " on workgroup %s, subnet %s. \n " ,
workgroup_name , unicast_subnet - > subnet_name ) ;
}
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
/* Send out a query to establish whether there's a
domain master broswer registered with WINS . If not ,
we can become a domain master browser .
*/
1997-12-13 17:16:07 +03:00
2003-08-23 05:59:14 +04:00
DEBUG ( 0 , ( " become_domain_master_browser_wins: querying WINS server from IP %s \
1997-12-13 17:16:07 +03:00
for domain master browser name % s on workgroup % s \ n " ,
2003-08-23 05:59:14 +04:00
inet_ntoa ( unicast_subnet - > myip ) , nmb_namestr ( & nmbname ) , workgroup_name ) ) ;
query_name ( unicast_subnet , workgroup_name , nmbname . name_type ,
become_domain_master_query_success ,
become_domain_master_query_fail ,
NULL ) ;
}
}
1997-12-13 17:16:07 +03:00
}
/****************************************************************************
Add the domain logon server and domain master browser names
if we are set up to do so .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void add_domain_names ( time_t t )
{
2003-08-23 05:59:14 +04:00
static time_t lastrun = 0 ;
if ( ( lastrun ! = 0 ) & & ( t < lastrun + ( CHECK_TIME_ADD_DOM_NAMES * 60 ) ) )
return ;
lastrun = t ;
/* Do the "internet group" - <1c> names. */
if ( lp_domain_logons ( ) )
add_logon_names ( ) ;
/* Do the domain master names. */
if ( lp_domain_master ( ) ) {
if ( we_are_a_wins_client ( ) ) {
/* We register the WORKGROUP<1b> name with the WINS
server first , and call add_domain_master_bcast ( )
only if this is successful .
This results in domain logon services being gracefully provided ,
as opposed to the aggressive nature of 1.9 .16 p2 to 1.9 .16 p11 .
1.9 .16 p2 to 1.9 .16 p11 - due to a bug in namelogon . c ,
cannot provide domain master / domain logon services .
*/
become_domain_master_browser_wins ( lp_workgroup ( ) ) ;
} else {
become_domain_master_browser_bcast ( lp_workgroup ( ) ) ;
}
}
1997-12-13 17:16:07 +03:00
}