1
0
mirror of https://github.com/samba-team/samba.git synced 2025-01-08 21:18:16 +03:00

modified become_master() to a state-based system. becoming a master

is now performed in stages: wait for each NetBIOS name to be
successfully registered before proceeding to the next stage.

tied implicit name registration and release (broadcast method) to the
same piece of code as explicit method (via WINS server).

created special_browser_name() function that checks __MSBROWSE__
name: this name is ignored by WINS servers apparently.

fixed likely incompatibility between refresh_my_names() and add_my_names().
(netbios entries were unlikely to be refreshed).

NOTE: none of these changes have been tested. at all.

lkcl
(This used to be commit 7719fb0652)
This commit is contained in:
Samba Release Account 1996-07-04 19:19:26 +00:00
parent 9a08bb015c
commit 7812ff0813
10 changed files with 286 additions and 157 deletions

View File

@ -79,6 +79,8 @@
enum name_source {STATUS_QUERY, LMHOSTS, REGISTER, SELF, DNS, DNSFAIL};
enum node_type {B_NODE=0, P_NODE=1, M_NODE=2, NBDD_NODE=3};
enum packet_type {NMB_PACKET, DGRAM_PACKET};
enum master_state { MST_NONE, MST_WON, MST_MSB, MST_BROWSER, MST_DOMAIN };
enum state_type
{
NAME_STATUS_MASTER_CHECK,
@ -149,6 +151,9 @@ struct work_record
struct server_record *serverlist;
/* stage of development from non-master to master browser / domain master */
enum master_state state;
/* work group info */
fstring work_group;
int token; /* used when communicating with backup browsers */
@ -159,6 +164,7 @@ struct work_record
int announce_interval;
BOOL needannounce;
/* election info */
BOOL RunningElection;
BOOL needelection;

View File

@ -1,8 +1,5 @@
/* This file is automatically generated with "make proto". DO NOT EDIT */
/*The following definitions come from - */
BOOL check_access(int snum);
BOOL allow_access(char *deny_list,char *allow_list,struct from_host *client);
BOOL fromhost(int sock,struct from_host *f);
@ -273,6 +270,10 @@ void check_master_browser(void);
void browser_gone(char *work_name, struct in_addr ip);
void send_election(struct subnet_record *d, char *group,uint32 criterion,
int timeup,char *name);
void name_unregister_work(struct subnet_record *d, char *name, int name_type);
void name_register_work(struct subnet_record *d, char *name, int name_type,
int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast);
void become_master(struct subnet_record *d, struct work_record *work);
void become_nonmaster(struct subnet_record *d, struct work_record *work,
int remove_type);
void run_elections(void);
@ -309,6 +310,7 @@ BOOL interpret_node_status(struct subnet_record *d,
BOOL send_mailslot_reply(char *mailslot,int fd,char *buf,int len,char *srcname,
char *dstname,int src_type,int dest_type,
struct in_addr dest_ip,struct in_addr src_ip);
BOOL special_browser_name(char *name, int type);
void remove_name(struct subnet_record *d, struct name_record *n);
void dump_names(void);
void load_netbios_names(void);

View File

@ -108,6 +108,7 @@ static struct work_record *make_workgroup(char *name)
work->ElectionCount = 0;
work->needelection = False;
work->needannounce = True;
work->state = MST_NONE;
/* make sure all token representations of workgroups are unique */

View File

@ -34,6 +34,7 @@ extern int DEBUGLEVEL;
extern pstring scope;
extern pstring myname;
extern struct in_addr ipzero;
/* machine comment for host announcements */
extern pstring ServerComment;
@ -149,32 +150,162 @@ void send_election(struct subnet_record *d, char *group,uint32 criterion,
}
/****************************************************************************
un-register a SELF name that got rejected.
if this name happens to be rejected when samba is in the process
of becoming a master browser (registering __MSBROWSE__, WORKGROUP(1d)
or WORKGROUP(1b)) then we must stop being a master browser. sad.
**************************************************************************/
void name_unregister_work(struct subnet_record *d, char *name, int name_type)
{
struct work_record *work;
remove_netbios_name(d,name,name_type,SELF,ipzero);
if (!(work = find_workgroupstruct(d, name, False))) return;
if (special_browser_name(name, name_type) ||
(AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 &&
(name_type == 0x1d || name_type == 0x1b)))
{
int remove_type = 0;
if (special_browser_name(name, name_type))
remove_type = SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER;
if (name_type == 0x1d)
remove_type = SV_TYPE_MASTER_BROWSER;
if (name_type == 0x1b)
remove_type = SV_TYPE_DOMAIN_MASTER;
become_nonmaster(d, work, remove_type);
}
}
/****************************************************************************
registers a name.
if the name being added is a SELF name, we must additionally check
whether to proceed to the next stage in samba becoming a master browser.
**************************************************************************/
void name_register_work(struct subnet_record *d, char *name, int name_type,
int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast)
{
enum name_source source = ismyip(ip) ? SELF : REGISTER;
if (source == SELF)
{
struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False);
if (work && work->state != MST_NONE)
{
/* samba is in the process of working towards master browser-ness.
initiate the next stage.
*/
become_master(d, work);
}
}
add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast);
}
/*******************************************************************
become the master browser
become the master browser.
this is done in stages. note that this could take a while,
particularly on a broadcast subnet, as we have to wait for
the implicit registration of each name to be accepted.
as each name is successfully registered, become_master() is
called again, in order to initiate the next stage. see
dead_netbios_entry() - deals with implicit name registration
and response_name_reg() - deals with explicit registration
with a WINS server.
stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1.
stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d)
stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b)
stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...)
XXXX note: this code still does not cope with the distinction
between different types of nodes, particularly between M and P
nodes. that comes later.
******************************************************************/
static void become_master(struct subnet_record *d, struct work_record *work)
void become_master(struct subnet_record *d, struct work_record *work)
{
uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_SERVER_UNIX|0x00400000;
if (!work) return;
DEBUG(2,("Becoming master for %s\n",work->work_group));
DEBUG(2,("Becoming master for %s (stage %d)",work->work_group,work->state));
switch (work->state)
{
case MST_NONE: /* while we were nothing but a server... */
{
work->state = MST_WON; /* election win was successful */
work->ServerType |= SV_TYPE_MASTER_BROWSER;
work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
work->ElectionCriterion |= 0x5;
/* add browse, master and general names to database or register with WINS */
/* update our server status */
work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
DEBUG(2,("first stage: register ^1^2__MSBROWSE__^2^1\n"));
/* add special browser name */
add_my_name_entry(d,MSBROWSE ,0x01,NB_ACTIVE|NB_GROUP);
break;
}
case MST_WON: /* while nothing had happened except we won an election... */
{
work->state = MST_MSB; /* registering MSBROWSE was successful */
/* add server entry on successful registration of MSBROWSE */
add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
DEBUG(2,("second stage: register as master browser\n"));
/* add master name */
add_my_name_entry(d,work->work_group,0x1d,NB_ACTIVE );
break;
}
case MST_MSB: /* while we were still only registered MSBROWSE state */
{
work->state = MST_BROWSER; /* registering WORKGROUP(1d) was successful */
/* update our server status */
work->ServerType |= SV_TYPE_MASTER_BROWSER;
add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
if (d->my_interface && work->serverlist == NULL) /* no servers! */
{
/* ask all servers on our local net to announce to us */
announce_request(work, d->bcast_ip);
}
if (lp_domain_master())
{
DEBUG(4,("Domain master: adding names...\n"));
/* add domain master and domain member names or register with WINS */
DEBUG(2,("third stage: register as domain master\n"));
/* add domain master name */
add_my_name_entry(d,work->work_group,0x1b,NB_ACTIVE );
}
break;
}
case MST_BROWSER: /* while we were still a master browser... */
{
work->state = MST_DOMAIN; /* registering WORKGROUP(1b) was successful */
/* update our server status */
if (lp_domain_master())
{
work->ServerType |= SV_TYPE_DOMAIN_MASTER;
if (lp_domain_logons())
@ -182,16 +313,18 @@ static void become_master(struct subnet_record *d, struct work_record *work)
work->ServerType |= SV_TYPE_DOMAIN_CTRL;
work->ServerType |= SV_TYPE_DOMAIN_MEMBER;
}
DEBUG(2,("fourth stage: samba is now a domain master.\n"));
add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
}
/* update our server status */
add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
if (d->my_interface)
break;
}
case MST_DOMAIN:
{
/* ask all servers on our local net to announce to us */
announce_request(work, d->bcast_ip);
/* nothing else to become, at the moment: we are top-dog. */
DEBUG(2,("fifth stage: there isn't one yet!\n"));
break;
}
}
}
@ -222,6 +355,7 @@ void become_nonmaster(struct subnet_record *d, struct work_record *work,
work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
work->ElectionCriterion &= ~0x4;
work->state = MST_NONE;
/* announce ourselves as no longer active as a master browser. */
announce_server(d, work, work->work_group, myname, 0, 0);
@ -231,11 +365,20 @@ void become_nonmaster(struct subnet_record *d, struct work_record *work,
work->ServerType = new_server_type;
if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
{
if (work->state == MST_DOMAIN)
work->state = MST_BROWSER;
remove_name_entry(d,work->work_group,0x1b);
}
if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
{
if (work->state >= MST_BROWSER)
work->state = MST_NONE;
remove_name_entry(d,work->work_group,0x1d);
}
}
/*******************************************************************
@ -270,6 +413,8 @@ void run_elections(void)
work->work_group,inet_ntoa(d->bcast_ip)));
work->RunningElection = False;
work->state = MST_NONE;
become_master(d, work);
}
}
@ -340,6 +485,7 @@ void process_election(struct packet_struct *p,char *buf)
{
work->needelection = True;
work->ElectionCount=0;
work->state = MST_NONE;
}
}
else

View File

@ -52,7 +52,7 @@ static void update_name_trn_id(void)
/***************************************************************************
add an initated name query into the list
add an expected response record into the list
**************************************************************************/
static void add_response_record(struct subnet_record *d,
struct response_record *n)
@ -77,6 +77,21 @@ static void add_response_record(struct subnet_record *d,
}
/***************************************************************************
remove an expected response record from the list
**************************************************************************/
static void remove_response_record(struct subnet_record *d,
struct response_record *n)
{
if (n->prev) n->prev->next = n->next;
if (n->next) n->next->prev = n->prev;
if (d->responselist == n) d->responselist = n->next;
free(n);
}

/***************************************************************************
deals with an entry before it dies
**************************************************************************/
@ -138,11 +153,12 @@ static void dead_netbios_entry(struct subnet_record *d,
if (ismyip(n->to_ip))
{
remove_netbios_name(d,n->name.name,n->name.name_type,SELF,n->to_ip);
name_unregister_work(d,n->name.name,n->name.name_type);
}
if (!n->bcast)
{
DEBUG(1,("WINS server did not respond to name release!\n"));
DEBUG(0,("WINS server did not respond to name release!\n"));
/* XXXX whoops. we have problems. must deal with this */
}
break;
}
@ -161,10 +177,8 @@ static void dead_netbios_entry(struct subnet_record *d,
/* IMPORTANT: see response_name_reg() */
enum name_source source = ismyip(n->to_ip) ? SELF : REGISTER;
add_netbios_entry(d,n->name.name,n->name.name_type,
n->nb_flags, n->ttl, source,n->to_ip, True,!n->bcast);
name_register_work(d,n->name.name,n->name.name_type,
n->nb_flags, n->ttl, n->to_ip, n->bcast);
}
else
{
@ -175,6 +189,7 @@ static void dead_netbios_entry(struct subnet_record *d,
broadcasting. */
DEBUG(1,("WINS server did not respond to name registration!\n"));
/* XXXX whoops. we have problems. must deal with this */
}
break;
}
@ -295,19 +310,12 @@ void expire_netbios_response_entries()
}
else
{
dead_netbios_entry(d,n);
nextn = n->next;
if (n->prev) n->prev->next = n->next;
if (n->next) n->next->prev = n->prev;
if (d->responselist == n) d->responselist = n->next;
free(n);
num_response_packets--;
dead_netbios_entry (d,n); /* process the non-response */
remove_response_record(d,n); /* remove the non-response */
continue;
}
}

View File

@ -70,9 +70,28 @@ static struct subnet_record *find_req_subnet(struct in_addr ip, BOOL bcast)
****************************************************************************/
static BOOL name_equal(struct nmb_name *n1,struct nmb_name *n2)
{
if (n1->name_type != n2->name_type) return(False);
return n1->name_type == n2->name_type &&
strequal(n1->name ,n2->name ) &&
strequal(n1->scope,n2->scope);
}
return(strequal(n1->name,n2->name) && 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()).
WINS is configured to ignore this 'special browser name', presumably
because it's redundant: there's no such thing as an announceable
domain when dealing with a wide area network and a WINS server.
**************************************************************************/
BOOL special_browser_name(char *name, int type)
{
return strequal(name,MSBROWSE) && type == 0x01;
}
@ -344,7 +363,7 @@ void load_netbios_names(void)
name,type, inet_ntoa(ipaddr), ttd, nb_flags));
/* add all entries that have 60 seconds or more to live */
if (ttd - 10 < time(NULL) || ttd == 0)
if (ttd - 60 < time(NULL) || ttd == 0)
{
time_t t = (ttd?ttd-time(NULL):0) / 3;
@ -369,7 +388,7 @@ void remove_netbios_name(struct subnet_record *d,
int search = FIND_LOCAL;
/* if it's not a special browser name, search the WINS database */
if (type != 0x01 && type != 0x1d && type != 0x1e)
if (!special_browser_name(name, type))
search |= FIND_WINS;
make_nmb_name(&nn, name, type, scope);
@ -409,7 +428,7 @@ struct name_record *add_netbios_entry(struct subnet_record *d,
{
if (wins)
{
if (type == 0x01 || type == 0x1d || type == 0x1e)
if (special_browser_name(name, type))
{
/* XXXX WINS server supposed to ignore special browser names. hm.
but is a primary domain controller supposed to ignore special
@ -518,7 +537,10 @@ void add_my_name_entry(struct subnet_record *d,char *name,int type,int nb_flags)
re_reg = True;
/* always add our own entries */
add_netbios_entry(d,name,type,nb_flags,0,SELF,ipzero,False,lp_wins_support());
/* a time-to-live allows us to refresh this name with the WINS server. */
add_netbios_entry(d,name,type,
nb_flags,GET_TTL(0),
SELF,ipzero,False,lp_wins_support());
/* XXXX BUG: if samba is offering WINS support, it should still add the
name entry to a local-subnet name database. see rfc1001.txt 15.1.1 p28
@ -558,11 +580,14 @@ void add_my_names(void)
for (d = subnetlist; d; d = d->next)
{
/* these names need to be refreshed with the WINS server */
add_my_name_entry(d, myname,0x20,NB_ACTIVE);
add_my_name_entry(d, myname,0x03,NB_ACTIVE);
add_my_name_entry(d, myname,0x00,NB_ACTIVE);
add_my_name_entry(d, myname,0x1f,NB_ACTIVE);
/* these names are added permanently (ttl of zero) and will NOT be
refreshed with the WINS server */
add_netbios_entry(d,"*",0x0,NB_ACTIVE,0,SELF,ip,False,wins);
add_netbios_entry(d,"__SAMBA__",0x20,NB_ACTIVE,0,SELF,ip,False,wins);
add_netbios_entry(d,"__SAMBA__",0x00,NB_ACTIVE,0,SELF,ip,False,wins);
@ -615,7 +640,8 @@ void refresh_my_names(time_t t)
for (n = d->namelist; n; n = n->next)
{
/* each SELF name has an individual time to be refreshed */
if (n->source == SELF && n->refresh_time < time(NULL))
if (n->source == SELF && n->refresh_time < time(NULL) &&
n->death_time != 0)
{
add_my_name_entry(d,n->name.name,n->name.name_type,n->nb_flags);
}
@ -836,20 +862,15 @@ void response_name_reg(struct subnet_record *d, struct packet_struct *p)
/* IMPORTANT: see expire_netbios_response_entries() */
int nb_flags = nmb->answers->rdata[0];
struct in_addr found_ip;
int ttl = nmb->answers->ttl;
enum name_source source = REGISTER;
struct in_addr found_ip;
putip((char*)&found_ip,&nmb->answers->rdata[2]);
if (ismyip(found_ip)) source = SELF;
add_netbios_entry(d, name,type,nb_flags,ttl,source,found_ip,True,!bcast);
name_register_work(d,name,type,nb_flags,ttl,found_ip,bcast);
}
else
{
struct work_record *work;
DEBUG(1,("name registration for %s rejected!\n",
namestr(&nmb->question.question_name)));
@ -857,18 +878,7 @@ void response_name_reg(struct subnet_record *d, struct packet_struct *p)
been rejected: e.g if it was our GROUP(1d) name, we must unbecome
a master browser. */
remove_netbios_name(d,name,type,SELF,ipzero);
if (!(work = find_workgroupstruct(d, name, False))) return;
if (AM_MASTER(work) && (type == 0x1d || type == 0x1b))
{
int remove_type = 0;
if (type == 0x1d) remove_type = SV_TYPE_MASTER_BROWSER;
if (type == 0x1b) remove_type = SV_TYPE_DOMAIN_MASTER;
become_nonmaster(d, work, remove_type);
}
name_unregister_work(d,name,type);
}
}
@ -1253,27 +1263,6 @@ void reply_name_query(struct packet_struct *p)
struct name_record *n;
int search = 0;
if (name_type == 0x20 || name_type == 0x00 || name_type == 0x1b ||
name_type == 0x1f || name_type == 0x03 || name_type == 0x01 ||
name_type == 0x1c)
{
/* search for any of the non-'special browser' names, or for a PDC type
(0x1b) name in the WINS database.
XXXX should we include name type 0x1c: WINS server type?
*/
search |= FIND_WINS;
}
else
{
/* special browser name types e.g
^1^2__MSBROWSE__^2^1, GROUP(1d) and GROUP(1e)
name_type == 0x01 || name_type == 0x1d || name_type == 0x1e.
XXXX luke reckons we should be able to search for any SELF name
in the WINS database, if we are a primary domain controller.
*/
if (!(d = find_req_subnet(p->ip, bcast)))
{
DEBUG(3,("name query: bcast %s not known\n",
@ -1281,15 +1270,16 @@ void reply_name_query(struct packet_struct *p)
success = False;
}
/* XXXX delete if shouldn't search for SELF names in WINS database */
search |= FIND_WINS;
}
if (bcast)
{
/* a name query has been made by a non-WINS configured host. search the
local interface database as well */
search |= FIND_LOCAL;
}
else if (!special_browser_name(question->name, name_type))
{
search |= FIND_WINS;
}
DEBUG(3,("Name query "));
@ -1574,7 +1564,7 @@ static BOOL response_problem_check(struct response_record *n,
case NAME_QUERY_MST_SRV_CHK:
case NAME_QUERY_SRV_CHK:
case NAME_QUERY_MST_CHK:
/* don't do case NAME_QUERY_FIND_MST: MSBROWSE isn't a unique name. */
/* don't do case NAME_QUERY_FIND_MST */
{
if (!strequal(qname,n->name.name))
{
@ -1662,8 +1652,8 @@ static BOOL response_compatible(struct response_record *n,
default:
{
DEBUG(0,("unknown state type received in response_netbios_packet\n"));
break;
DEBUG(1,("unknown state type received in response_netbios_packet\n"));
return False;
}
}
return True;
@ -1724,7 +1714,7 @@ static void response_process(struct subnet_record *d, struct packet_struct *p,
default:
{
DEBUG(0,("unknown state type received in response_netbios_packet\n"));
DEBUG(1,("unknown state type received in response_netbios_packet\n"));
break;
}
}

View File

@ -747,45 +747,32 @@ struct srv_info_struct
/*******************************************************************
filter out unwanted server info
This function returns True if the entry is wanted.
******************************************************************/
static BOOL filter_server_info(struct srv_info_struct *server,
BOOL domains,
char *domain, uint32 request)
{
/* If no domain was specified, */
if (*domain == 0)
{
/* If entry's domain matches this server's domain,
accept this entry. */
if (strequal(lp_workgroup(), server->domain)) {
return True;
}
/* If specific domain requested, reject this entry. */
else if (domains)
{
DEBUG(4,("primary domain:reject %8x %s %s\n",request,server->name,server->domain));
return False;
}
/* If the request was for a list of domain enumerators,
we don't care what domain this entry is in as long
as it is a domain enumerator. */
else if ((request & SV_TYPE_DOMAIN_ENUM) &&
(server->type & SV_TYPE_DOMAIN_ENUM))
{
return True;
}
DEBUG(4,("wrong domain: %8x: %s %s\n",server->type,server->name,server->domain));
DEBUG(4,("rej:DOM %8x: %s %s\n",server->type,server->name,server->domain));
return False;
}
/* If a domain name was specified, */
return True;
}
else
{
/* If this entry is in the requested domain, */
if (strequal(domain, server->domain))
{
/*
@ -805,15 +792,11 @@ static BOOL filter_server_info(struct srv_info_struct *server,
return True;
}
/* If the user didn't pick a domain,
(I don't think this can happen.) */
else if (!domains)
{
DEBUG(4,("domain:%s %s %s\n",domain,server->name,server->domain));
return False;
}
return True;
}
}
@ -888,7 +871,6 @@ static int get_server_info(uint32 servertype,
ok = False;
}
/* If all server, reject DOMIAN_ENUM entries? */
if ((servertype == ~SV_TYPE_DOMAIN_ENUM) &&
(s->type & SV_TYPE_DOMAIN_ENUM))
{
@ -896,8 +878,6 @@ static int get_server_info(uint32 servertype,
ok = False;
}
/* If a domain is specified, reject all except the
domain enumerators for the specified domain. */
if (domains && !(domain && *domain && strequal(domain, s->domain)))
{
if (!(s->type & SV_TYPE_DOMAIN_ENUM))
@ -1055,13 +1035,11 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
if (strcmp(str1, "WrLehDO") == 0)
{
domains = False;
DEBUG(4, ("all domains\n"));
}
else if (strcmp(str1, "WrLehDz") == 0)
{
domains = True;
StrnCpy(domain, p, sizeof(fstring)-1);
DEBUG(4, ("domains must match \"%s\"\n", domains));
}
if (lp_browse_list())
@ -1073,7 +1051,6 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
qsort(servers,total,sizeof(servers[0]),QSORT_CAST srv_comp);
/* A dry run */
{
char *lastname=NULL;
@ -1108,7 +1085,6 @@ static BOOL api_RNetServerEnum(int cnum, int uid, char *param, char *data,
f_len = fixed_len;
s_len = string_len;
/* the real thing */
{
char *lastname=NULL;
int count2 = counted;