summaryrefslogtreecommitdiff
path: root/source3/nameelect.c
diff options
context:
space:
mode:
authorAndrew Tridgell <tridge@samba.org>1996-06-04 06:42:03 +0000
committerAndrew Tridgell <tridge@samba.org>1996-06-04 06:42:03 +0000
commita2c1623827406667a4f2f058c24f1d971f6627f8 (patch)
tree22350c4c3fe902a1b573612d40a6ca4d2be51856 /source3/nameelect.c
parent81e398963dbaed9c6661c336fe98329098576b94 (diff)
downloadsamba-a2c1623827406667a4f2f058c24f1d971f6627f8.tar.gz
samba-a2c1623827406667a4f2f058c24f1d971f6627f8.tar.bz2
samba-a2c1623827406667a4f2f058c24f1d971f6627f8.zip
a huge pile of changes :-)
The biggest thing is the integration of Lukes new nmbd. Its still largely untested, so we will really need some feedback I've also added auto prototype generation and cleaned up a lot of minor things as a result (This used to be commit 0d8dcfa13c527ec2c8aca39ba49c09e4e694b26c)
Diffstat (limited to 'source3/nameelect.c')
-rw-r--r--source3/nameelect.c371
1 files changed, 371 insertions, 0 deletions
diff --git a/source3/nameelect.c b/source3/nameelect.c
new file mode 100644
index 0000000000..30c3c3795e
--- /dev/null
+++ b/source3/nameelect.c
@@ -0,0 +1,371 @@
+/*
+ Unix SMB/Netbios implementation.
+ Version 1.9.
+ NBT netbios routines and daemon - version 2
+ Copyright (C) Andrew Tridgell 1994-1995
+
+ 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 02139, USA.
+
+ Revision History:
+
+ 14 jan 96: lkcl@pires.co.uk
+ added multiple workgroup domain master support
+
+*/
+
+#include "includes.h"
+#include "loadparm.h"
+#include "localnet.h"
+
+extern int DEBUGLEVEL;
+extern pstring scope;
+
+extern pstring myname;
+
+/* machine comment for host announcements */
+extern pstring ServerComment;
+
+/* here are my election parameters */
+
+/* NTAS uses 2, NT uses 1, WfWg uses 0 */
+#define MAINTAIN_LIST 2
+#define ELECTION_VERSION 2
+
+extern time_t StartupTime;
+
+#define AM_MASTER(work) (work->ServerType & SV_TYPE_MASTER_BROWSER)
+
+#define MSBROWSE "\001\002__MSBROWSE__\002"
+#define BROWSE_MAILSLOT "\\MAILSLOT\\BROWSE"
+
+extern struct domain_record *domainlist;
+
+
+/*******************************************************************
+ occasionally check to see if the master browser is around
+ ******************************************************************/
+void check_master_browser(void)
+{
+ static time_t lastrun=0;
+ time_t t = time(NULL);
+ struct domain_record *d;
+
+ if (!lastrun) lastrun = t;
+ if (t < lastrun + 2*60) return;
+ lastrun = t;
+
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ /* if we are not the browse master of a workgroup, and we can't
+ find a browser on the subnet, do something about it. */
+
+ if (!AM_MASTER(work))
+ {
+ queue_netbios_packet(ClientNMB,NMB_QUERY,CHECK_MASTER,
+ work->work_group,0x1d,0,
+ True,False,d->bcast_ip);
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+ what to do if a master browser DOESN't exist
+ ******************************************************************/
+void browser_gone(char *work_name, struct in_addr ip)
+{
+ struct domain_record *d = find_domain(ip);
+ struct work_record *work = find_workgroupstruct(d, work_name, False);
+
+ if (!work || !d) return;
+
+ DEBUG(2,("Forcing election on %s\n",work->work_group));
+
+ if (strequal(work->work_group, lp_workgroup()) &&
+ ip_equal(bcast_ip, d->bcast_ip))
+ {
+ /* we can attempt to become master browser */
+ work->needelection = True;
+ }
+ else
+ {
+ DEBUG(2,("no master browser for persistent entry %s %s\n",
+ work->work_group, inet_ntoa(d->bcast_ip)));
+
+ /* XXXX oh dear. we are going to have problems here. the
+ entry is a persistent one, there isn't anyone responsible
+ for this workgroup up and running, yet we can't find it
+ and we are going to continually have name_queries until
+ a master browser is found for this workgroup on the
+ remote subnet.
+ */
+ }
+}
+/****************************************************************************
+ send an election packet
+ **************************************************************************/
+void send_election(struct domain_record *d, char *group,uint32 criterion,
+ int timeup,char *name)
+{
+ pstring outbuf;
+ char *p;
+
+ if (!d) return;
+
+ DEBUG(2,("Sending election to %s for workgroup %s\n",
+ inet_ntoa(d->bcast_ip),group));
+
+ bzero(outbuf,sizeof(outbuf));
+ p = outbuf;
+ CVAL(p,0) = 8; /* election */
+ p++;
+
+ CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
+ SIVAL(p,1,criterion);
+ SIVAL(p,5,timeup*1000); /* ms - despite the spec */
+ p += 13;
+ strcpy(p,name);
+ strupper(p);
+ p = skip_string(p,1);
+
+ send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
+ name,group,0,0x1e,d->bcast_ip,myip);
+}
+
+
+/*******************************************************************
+ become the master browser
+ ******************************************************************/
+static void become_master(struct domain_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));
+
+ 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 */
+ add_name_entry(MSBROWSE ,0x01,NB_ACTIVE|NB_GROUP);
+ add_name_entry(work->work_group,0x1d,NB_ACTIVE );
+
+ if (lp_domain_master())
+ {
+ DEBUG(4,("Domain master: adding names...\n"));
+
+ /* add domain master and domain member names or register with WINS */
+ add_name_entry(work->work_group,0x1b,NB_ACTIVE );
+ add_name_entry(work->work_group,0x1c,NB_ACTIVE|NB_GROUP);
+
+ work->ServerType |= SV_TYPE_DOMAIN_MASTER;
+
+ if (lp_domain_logons())
+ {
+ work->ServerType |= SV_TYPE_DOMAIN_CTRL;
+ work->ServerType |= SV_TYPE_DOMAIN_MEMBER;
+ }
+ }
+
+ /* 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 (ip_equal(bcast_ip, d->bcast_ip))
+ {
+ /* ask all servers on our local net to announce to us */
+ announce_request(work, d->bcast_ip);
+ }
+}
+
+
+/*******************************************************************
+ unbecome the master browser
+ ******************************************************************/
+void become_nonmaster(struct domain_record *d, struct work_record *work)
+{
+ DEBUG(2,("Becoming non-master for %s\n",work->work_group));
+
+ work->ServerType &= ~SV_TYPE_MASTER_BROWSER;
+ work->ServerType &= ~SV_TYPE_DOMAIN_MASTER;
+ work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
+
+ work->ElectionCriterion &= ~0x4;
+
+ remove_name_entry(work->work_group,0x1b);
+ remove_name_entry(work->work_group,0x1c);
+ remove_name_entry(work->work_group,0x1d);
+ remove_name_entry(MSBROWSE ,0x01);
+}
+
+
+/*******************************************************************
+ run the election
+ ******************************************************************/
+void run_elections(void)
+{
+ time_t t = time(NULL);
+ static time_t lastime = 0;
+
+ struct domain_record *d;
+
+ /* send election packets once a second */
+ if (lastime && t-lastime <= 0) return;
+
+ lastime = t;
+
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (work->RunningElection)
+ {
+ send_election(d,work->work_group, work->ElectionCriterion,
+ t-StartupTime,myname);
+
+ if (work->ElectionCount++ >= 4)
+ {
+ /* I won! now what :-) */
+ DEBUG(2,(">>> Won election on %s <<<\n",work->work_group));
+
+ work->RunningElection = False;
+ become_master(d, work);
+ }
+ }
+ }
+ }
+}
+
+
+/*******************************************************************
+ work out if I win an election
+ ******************************************************************/
+static BOOL win_election(struct work_record *work,int version,uint32 criterion,
+ int timeup,char *name)
+{
+ time_t t = time(NULL);
+ uint32 mycriterion;
+ if (version > ELECTION_VERSION) return(False);
+ if (version < ELECTION_VERSION) return(True);
+
+ mycriterion = work->ElectionCriterion;
+
+ if (criterion > mycriterion) return(False);
+ if (criterion < mycriterion) return(True);
+
+ if (timeup > (t - StartupTime)) return(False);
+ if (timeup < (t - StartupTime)) return(True);
+
+ if (strcasecmp(myname,name) > 0) return(False);
+
+ return(True);
+}
+
+
+/*******************************************************************
+ process a election packet
+
+ An election dynamically decides who will be the master.
+ ******************************************************************/
+void process_election(struct packet_struct *p,char *buf)
+{
+ struct dgram_packet *dgram = &p->packet.dgram;
+ struct in_addr ip = dgram->header.source_ip;
+ struct domain_record *d = find_domain(ip);
+ int version = CVAL(buf,0);
+ uint32 criterion = IVAL(buf,1);
+ int timeup = IVAL(buf,5)/1000;
+ char *name = buf+13;
+ struct work_record *work;
+
+ if (!d) return;
+
+ name[15] = 0;
+
+ DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n",
+ name,version,criterion,timeup));
+
+ if (same_context(dgram)) return;
+
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ if (listening_name(work, &dgram->dest_name) &&
+ strequal(work->work_group, lp_workgroup()) &&
+ ip_equal(d->bcast_ip, bcast_ip))
+ {
+ if (win_election(work, version,criterion,timeup,name))
+ {
+ if (!work->RunningElection)
+ {
+ work->needelection = True;
+ work->ElectionCount=0;
+ }
+ }
+ else
+ {
+ work->needelection = False;
+
+ if (work->RunningElection)
+ {
+ work->RunningElection = False;
+ DEBUG(3,(">>> Lost election on %s <<<\n",work->work_group));
+
+ /* if we are the master then remove our masterly names */
+ if (AM_MASTER(work))
+ {
+ become_nonmaster(d, work);
+ }
+ }
+ }
+ }
+ }
+}
+
+
+/****************************************************************************
+ checks whether a browser election is to be run on any workgroup
+ ***************************************************************************/
+BOOL check_elections(void)
+{
+ struct domain_record *d;
+ BOOL run_any_election = False;
+
+ for (d = domainlist; d; d = d->next)
+ {
+ struct work_record *work;
+ for (work = d->workgrouplist; work; work = work->next)
+ {
+ run_any_election |= work->RunningElection;
+
+ if (work->needelection && !work->RunningElection)
+ {
+ DEBUG(3,(">>> Starting election on %s <<<\n",work->work_group));
+ work->ElectionCount = 0;
+ work->RunningElection = True;
+ work->needelection = False;
+ }
+ }
+ }
+ return run_any_election;
+}
+