Large changes from jra@cygnus.com. Mainly browser updates.
[Samba.git] / source / nameelect.c
bloba11d0fb786775978595a946f612f352457d964a3
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1996
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 Module name: nameelect.c
23 Revision History:
25 14 jan 96: lkcl@pires.co.uk
26 added multiple workgroup domain master support
28 04 jul 96: lkcl@pires.co.uk
29 added system to become a master browser by stages.
34 #include "includes.h"
36 extern int ClientNMB;
37 extern int ClientDGRAM;
39 extern int DEBUGLEVEL;
40 extern pstring scope;
42 extern pstring myname;
43 extern struct in_addr ipzero;
44 extern struct in_addr wins_ip;
46 /* here are my election parameters */
48 extern time_t StartupTime;
50 extern struct subnet_record *subnetlist;
52 extern uint16 nb_type; /* samba's NetBIOS name type */
55 /*******************************************************************
56 occasionally check to see if the master browser is around
57 ******************************************************************/
58 void check_master_browser(time_t t)
60 static time_t lastrun=0;
61 struct subnet_record *d;
63 if (!lastrun) lastrun = t;
64 if (t < lastrun + CHECK_TIME_MST_BROWSE * 60) return;
66 lastrun = t;
68 dump_workgroups();
70 for (d = subnetlist; d; d = d->next)
72 struct work_record *work;
74 /* don't do election stuff on the WINS subnet */
75 if (ip_equal(d->bcast_ip,wins_ip))
76 continue;
78 for (work = d->workgrouplist; work; work = work->next)
80 if (!AM_MASTER(work))
82 if (lp_preferred_master())
84 /* preferred master - not a master browser. force
85 becoming a master browser, hence the log message.
88 DEBUG(0,("%s preferred master for %s %s - force election\n",
89 timestring(), work->work_group,
90 inet_ntoa(d->bcast_ip)));
92 browser_gone(work->work_group, d->bcast_ip);
94 else
96 /* if we are not the browse master of a workgroup,
97 and we can't find a browser on the subnet, do
98 something about it.
101 queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
102 work->work_group,0x1d,0,0,0,NULL,NULL,
103 True,False,d->bcast_ip,d->bcast_ip);
111 /*******************************************************************
112 what to do if a master browser DOESN't exist
113 ******************************************************************/
114 void browser_gone(char *work_name, struct in_addr ip)
116 struct subnet_record *d = find_subnet(ip);
117 struct work_record *work = find_workgroupstruct(d, work_name, False);
119 /* i don't know about this workgroup, therefore i don't care */
120 if (!work || !d) return;
122 /* don't do election stuff on the WINS subnet */
123 if (ip_equal(d->bcast_ip,wins_ip))
124 return;
126 if (strequal(work->work_group, lp_workgroup()))
129 DEBUG(2,("Forcing election on %s %s\n",
130 work->work_group,inet_ntoa(d->bcast_ip)));
132 /* we can attempt to become master browser */
133 work->needelection = True;
135 else
137 /* local interfaces: force an election */
138 send_election(d, work->work_group, 0, 0, myname);
140 /* only removes workgroup completely on a local interface
141 persistent lmhosts entries on a local interface _will_ be removed).
143 remove_workgroup(d, work,True);
148 /****************************************************************************
149 send an election packet
150 **************************************************************************/
151 void send_election(struct subnet_record *d, char *group,uint32 criterion,
152 int timeup,char *name)
154 pstring outbuf;
155 char *p;
157 if (!d) return;
159 DEBUG(2,("Sending election to %s for workgroup %s\n",
160 inet_ntoa(d->bcast_ip),group));
162 bzero(outbuf,sizeof(outbuf));
163 p = outbuf;
164 CVAL(p,0) = ANN_Election; /* election */
165 p++;
167 CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
168 SIVAL(p,1,criterion);
169 SIVAL(p,5,timeup*1000); /* ms - despite the spec */
170 p += 13;
171 strcpy(p,name);
172 strupper(p);
173 p = skip_string(p,1);
175 send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
176 outbuf,PTR_DIFF(p,outbuf),
177 name,group,0,0x1e,d->bcast_ip,*iface_ip(d->bcast_ip));
181 /****************************************************************************
182 un-register a SELF name that got rejected.
184 if this name happens to be rejected when samba is in the process
185 of becoming a master browser (registering __MSBROWSE__, WORKGROUP(1d)
186 or WORKGROUP(1b)) then we must stop being a master browser. sad.
188 **************************************************************************/
189 void name_unregister_work(struct subnet_record *d, char *name, int name_type)
191 struct work_record *work;
192 int remove_type_local = 0;
193 int remove_type_domain = 0;
194 int remove_type_logon = 0;
196 remove_netbios_name(d,name,name_type,SELF,ipzero);
198 if (!(work = find_workgroupstruct(d, name, False))) return;
200 /* work out what to unbecome, from the name type being removed */
202 if (ms_browser_name(name, name_type))
204 remove_type_local |= SV_TYPE_MASTER_BROWSER;
206 if (AM_MASTER(work) && strequal(name, lp_workgroup()) && name_type == 0x1d)
208 remove_type_local |= SV_TYPE_MASTER_BROWSER;
210 if (AM_DOMMST(work) && strequal(name, lp_workgroup()) && name_type == 0x1b)
212 remove_type_domain |= SV_TYPE_DOMAIN_MASTER;
214 if (AM_DOMMEM(work) && strequal(name, lp_workgroup()) && name_type == 0x1c)
216 remove_type_logon|= SV_TYPE_DOMAIN_MEMBER;
219 if (remove_type_local ) unbecome_local_master (d, work, remove_type_local );
220 if (remove_type_domain) unbecome_domain_master(d, work, remove_type_domain);
221 if (remove_type_logon ) unbecome_logon_server (d, work, remove_type_logon );
225 /****************************************************************************
226 registers a name.
228 if the name being added is a SELF name, we must additionally check
229 whether to proceed to the next stage in samba becoming a master browser.
231 **************************************************************************/
232 void name_register_work(struct subnet_record *d, char *name, int name_type,
233 int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast)
235 enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ?
236 SELF : REGISTER;
238 if (source == SELF)
240 struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False);
242 add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast);
244 if (work)
246 int add_type_local = False;
247 int add_type_domain = False;
248 int add_type_logon = False;
250 DEBUG(4,("checking next stage: name_register_work %s\n", name));
252 /* work out what to become, from the name type being added */
254 if (ms_browser_name(name, name_type))
256 add_type_local = True;
258 if (strequal(name, lp_workgroup()) && name_type == 0x1d)
260 add_type_local = True;
262 if (strequal(name, lp_workgroup()) && name_type == 0x1b)
264 add_type_domain = True;
266 if (strequal(name, lp_workgroup()) && name_type == 0x1c)
268 add_type_logon = True;
271 if (add_type_local ) become_local_master (d, work);
272 if (add_type_domain) become_domain_master(d, work);
273 if (add_type_logon ) become_logon_server (d, work);
279 /*******************************************************************
280 become the local master browser.
282 this is done in stages. note that this could take a while,
283 particularly on a broadcast subnet, as we have to wait for
284 the implicit registration of each name to be accepted.
286 as each name is successfully registered, become_local_master() is
287 called again, in order to initiate the next stage. see
288 dead_netbios_entry() - deals with implicit name registration
289 and response_name_reg() - deals with explicit registration
290 with a WINS server.
292 stage 1: was MST_POTENTIAL - go to MST_POTENTIAL and register ^1^2__MSBROWSE__^2^1.
293 stage 2: was MST_BACK - go to MST_MSB and register WORKGROUP(0x1d)
294 stage 3: was MST_MSB - go to MST_BROWSER and stay there
296 XXXX note: this code still does not cope with the distinction
297 between different types of nodes, particularly between M and P
298 nodes. that comes later.
300 ******************************************************************/
301 void become_local_master(struct subnet_record *d, struct work_record *work)
303 /* domain type must be limited to domain enum + server type. it must
304 not have SV_TYPE_SERVER or anything else with SERVER in it, else
305 clients get confused and start thinking this entry is a server
306 not a workgroup
308 uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
310 if (!work || !d) return;
312 DEBUG(2,("Becoming master for %s %s (currently at stage %d)\n",
313 work->work_group,inet_ntoa(d->bcast_ip),work->mst_state));
315 switch (work->mst_state)
317 case MST_POTENTIAL: /* while we were nothing but a server... */
319 DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n"));
320 work->mst_state = MST_BACK; /* ... an election win was successful */
322 work->ElectionCriterion |= 0x5;
324 /* update our server status */
325 work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
326 add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True);
328 /* add special browser name */
329 add_my_name_entry(d,MSBROWSE ,0x01,nb_type|NB_ACTIVE|NB_GROUP);
331 /* DON'T do anything else after calling add_my_name_entry() */
332 break;
335 case MST_BACK: /* while nothing had happened except we won an election... */
337 DEBUG(3,("go to second stage: register as master browser\n"));
338 work->mst_state = MST_MSB; /* ... registering MSBROWSE was successful */
340 /* add server entry on successful registration of MSBROWSE */
341 add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
343 /* add master name */
344 add_my_name_entry(d,work->work_group,0x1d,nb_type|NB_ACTIVE);
346 /* DON'T do anything else after calling add_my_name_entry() */
347 break;
350 case MST_MSB: /* while we were still only registered MSBROWSE state... */
352 DEBUG(3,("2nd stage complete: registered as master browser\n"));
353 work->mst_state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */
355 /* update our server status */
356 work->ServerType |= SV_TYPE_MASTER_BROWSER;
358 DEBUG(3,("become_local_master: updating our server %s to type %x\n", myname, work->ServerType));
360 add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True);
362 if (work->serverlist == NULL) /* no servers! */
364 /* ask all servers on our local net to announce to us */
365 /* XXXX OOPS! add_server_entry will always add one entry - our own. */
366 announce_request(work, d->bcast_ip);
368 break;
371 case MST_BROWSER:
373 /* don't have to do anything: just report success */
374 DEBUG(3,("3rd stage: become master browser!\n"));
376 break;
382 /*******************************************************************
383 become the domain master browser.
385 this is done in stages. note that this could take a while,
386 particularly on a broadcast subnet, as we have to wait for
387 the implicit registration of each name to be accepted.
389 as each name is successfully registered, become_domain_master() is
390 called again, in order to initiate the next stage. see
391 dead_netbios_entry() - deals with implicit name registration
392 and response_name_reg() - deals with explicit registration
393 with a WINS server.
395 stage 1: was DOMAIN_NONE - go to DOMAIN_MST
397 XXXX note: this code still does not cope with the distinction
398 between different types of nodes, particularly between M and P
399 nodes. that comes later.
401 ******************************************************************/
402 void become_domain_master(struct subnet_record *d, struct work_record *work)
404 /* domain type must be limited to domain enum + server type. it must
405 not have SV_TYPE_SERVER or anything else with SERVER in it, else
406 clients get confused and start thinking this entry is a server
407 not a workgroup
410 if ((!work) || (!d)) return;
412 DEBUG(2,("Becoming domain master for %s %s (currently at stage %d)\n",
413 work->work_group,inet_ntoa(d->bcast_ip),work->dom_state));
415 switch (work->dom_state)
417 case DOMAIN_NONE: /* while we were nothing but a server... */
419 if (lp_domain_master())
421 DEBUG(3,("go to first stage: register <1b> name\n"));
422 work->dom_state = DOMAIN_WAIT;
424 /* XXXX the 0x1b is domain master browser name */
425 add_my_name_entry(d, lp_workgroup(),0x1b,nb_type|NB_ACTIVE|NB_GROUP);
427 /* DON'T do anything else after calling add_my_name_entry() */
428 break;
430 else
432 DEBUG(4,("samba not configured as a domain master.\n"));
435 break;
438 case DOMAIN_WAIT:
440 if (lp_domain_master())
442 work->dom_state = DOMAIN_MST; /* ... become domain master */
443 DEBUG(3,("domain first stage: register as domain member\n"));
445 /* update our server status */
446 work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER;
447 add_server_entry(d,work,myname,work->ServerType,0,
448 lp_serverstring(),True);
450 DEBUG(4,("samba is now a domain master\n"));
452 break;
454 else
456 DEBUG(4,("samba not configured as a domain master.\n"));
459 break;
462 case DOMAIN_MST:
464 /* don't have to do anything: just report success */
465 DEBUG(3,("domain second stage: there isn't one!\n"));
466 break;
472 /*******************************************************************
473 become a logon server.
474 ******************************************************************/
475 void become_logon_server(struct subnet_record *d, struct work_record *work)
477 if (!work || !d) return;
479 DEBUG(2,("Becoming logon server for %s %s (currently at stage %d)\n",
480 work->work_group,inet_ntoa(d->bcast_ip),work->log_state));
482 switch (work->log_state)
484 case LOGON_NONE: /* while we were nothing but a server... */
486 if (lp_domain_logons())
488 DEBUG(3,("go to first stage: register <1c> name\n"));
489 work->log_state = LOGON_WAIT;
491 /* XXXX the 0x1c is apparently something to do with domain logons */
492 add_my_name_entry(d, lp_workgroup(),0x1c,nb_type|NB_ACTIVE|NB_GROUP);
494 /* DON'T do anything else after calling add_my_name_entry() */
495 break;
498 DEBUG(4,("samba not configured as a logon master.\n"));
501 break;
504 case LOGON_WAIT:
506 if (lp_domain_logons())
508 work->log_state = LOGON_SRV; /* ... become logon server */
509 DEBUG(3,("logon second stage: register \n"));
511 /* update our server status */
512 work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MEMBER;
513 add_server_entry(d,work,myname,work->ServerType,0,
514 lp_serverstring(),True);
516 /* DON'T do anything else after calling add_my_name_entry() */
517 break;
519 else
521 DEBUG(4,("samba not configured as a logon server.\n"));
524 break;
527 case LOGON_SRV:
529 DEBUG(3,("logon third stage: there isn't one!\n"));
530 break;
537 /*******************************************************************
538 unbecome the local master browser. initates removal of necessary netbios
539 names, and tells the world that we are no longer a master browser.
541 XXXX this _should_ be used to demote to a backup master browser, without
542 going straight to non-master browser. another time.
544 ******************************************************************/
545 void unbecome_local_master(struct subnet_record *d, struct work_record *work,
546 int remove_type)
548 int new_server_type = work->ServerType;
550 /* can only remove master types with this function */
551 remove_type &= SV_TYPE_MASTER_BROWSER;
553 new_server_type &= ~remove_type;
555 if (remove_type)
557 DEBUG(2,("Becoming local non-master for %s\n",work->work_group));
559 /* no longer a master browser of any sort */
561 work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
562 work->ElectionCriterion &= ~0x4;
563 work->mst_state = MST_POTENTIAL;
565 /* announce ourselves as no longer active as a master browser. */
566 announce_server(d, work, work->work_group, myname, 0, 0);
567 remove_name_entry(d,MSBROWSE ,0x01);
568 remove_name_entry(d,work->work_group,0x1d);
573 /*******************************************************************
574 unbecome the domain master browser. initates removal of necessary netbios
575 names, and tells the world that we are no longer a domain browser.
576 ******************************************************************/
577 void unbecome_domain_master(struct subnet_record *d, struct work_record *work,
578 int remove_type)
580 int new_server_type = work->ServerType;
582 DEBUG(2,("Becoming domain non-master for %s\n",work->work_group));
584 /* can only remove master or domain types with this function */
585 remove_type &= SV_TYPE_DOMAIN_MASTER;
587 new_server_type &= ~remove_type;
589 if (remove_type)
591 /* no longer a domain master browser of any sort */
593 work->dom_state = DOMAIN_NONE;
595 /* announce ourselves as no longer active as a master browser. */
596 announce_server(d, work, work->work_group, myname, 0, 0);
597 remove_name_entry(d,work->work_group,0x1b);
602 /*******************************************************************
603 unbecome the logon server. initates removal of necessary netbios
604 names, and tells the world that we are no longer a logon server.
605 ******************************************************************/
606 void unbecome_logon_server(struct subnet_record *d, struct work_record *work,
607 int remove_type)
609 int new_server_type = work->ServerType;
611 DEBUG(2,("Becoming logon non-server for %s\n",work->work_group));
613 /* can only remove master or domain types with this function */
614 remove_type &= SV_TYPE_DOMAIN_MEMBER;
616 new_server_type &= ~remove_type;
618 if (remove_type)
620 /* no longer a master browser of any sort */
622 work->log_state = LOGON_NONE;
624 /* announce ourselves as no longer active as a master browser. */
625 announce_server(d, work, work->work_group, myname, 0, 0);
626 remove_name_entry(d,work->work_group,0x1c);
631 /*******************************************************************
632 run the election
633 ******************************************************************/
634 void run_elections(time_t t)
636 static time_t lastime = 0;
638 struct subnet_record *d;
640 /* send election packets once a second */
641 if (lastime && t-lastime <= 0) return;
643 lastime = t;
645 for (d = subnetlist; d; d = d->next)
647 struct work_record *work;
649 if(ip_equal(d->bcast_ip, wins_ip))
651 /* WINS ip */
652 DEBUG(10,("run_elections: ignoring WINS subnet\n"));
653 continue;
656 for (work = d->workgrouplist; work; work = work->next)
658 if (work->RunningElection)
660 send_election(d,work->work_group, work->ElectionCriterion,
661 t-StartupTime,myname);
663 if (work->ElectionCount++ >= 4)
665 /* I won! now what :-) */
666 DEBUG(2,(">>> Won election on %s %s <<<\n",
667 work->work_group,inet_ntoa(d->bcast_ip)));
669 work->RunningElection = False;
670 work->mst_state = MST_POTENTIAL;
672 become_local_master(d, work);
680 /*******************************************************************
681 work out if I win an election
682 ******************************************************************/
683 static BOOL win_election(struct work_record *work,int version,uint32 criterion,
684 int timeup,char *name)
686 int mytimeup = time(NULL) - StartupTime;
687 uint32 mycriterion = work->ElectionCriterion;
689 DEBUG(4,("election comparison: %x:%x %x:%x %d:%d %s:%s\n",
690 version,ELECTION_VERSION,
691 criterion,mycriterion,
692 timeup,mytimeup,
693 name,myname));
695 if (version > ELECTION_VERSION) return(False);
696 if (version < ELECTION_VERSION) return(True);
698 if (criterion > mycriterion) return(False);
699 if (criterion < mycriterion) return(True);
701 if (timeup > mytimeup) return(False);
702 if (timeup < mytimeup) return(True);
704 if (strcasecmp(myname,name) > 0) return(False);
706 return(True);
710 /*******************************************************************
711 process a election packet
713 An election dynamically decides who will be the master.
714 ******************************************************************/
715 void process_election(struct packet_struct *p,char *buf)
717 struct dgram_packet *dgram = &p->packet.dgram;
718 struct in_addr ip = dgram->header.source_ip;
719 struct subnet_record *d = find_subnet(ip);
720 int version = CVAL(buf,0);
721 uint32 criterion = IVAL(buf,1);
722 int timeup = IVAL(buf,5)/1000;
723 char *name = buf+13;
724 struct work_record *work;
726 if (!d) return;
728 if (ip_equal(d->bcast_ip,wins_ip)) {
729 DEBUG(3,("Unexpected election request from %s %s on WINS net\n",
730 name, inet_ntoa(p->ip)));
731 return;
734 name[15] = 0;
736 DEBUG(3,("Election request from %s %s vers=%d criterion=%08x timeup=%d\n",
737 name,inet_ntoa(p->ip),version,criterion,timeup));
739 if (same_context(dgram)) return;
741 for (work = d->workgrouplist; work; work = work->next)
743 if (!strequal(work->work_group, lp_workgroup()))
744 continue;
746 if (win_election(work, version,criterion,timeup,name)) {
747 if (!work->RunningElection) {
748 work->needelection = True;
749 work->ElectionCount=0;
750 work->mst_state = MST_POTENTIAL;
752 } else {
753 work->needelection = False;
755 if (work->RunningElection || AM_MASTER(work)) {
756 work->RunningElection = False;
757 DEBUG(3,(">>> Lost election on %s %s <<<\n",
758 work->work_group,inet_ntoa(d->bcast_ip)));
759 if (AM_MASTER(work))
760 unbecome_local_master(d, work, SV_TYPE_MASTER_BROWSER);
767 /****************************************************************************
768 checks whether a browser election is to be run on any workgroup
770 this function really ought to return the time between election
771 packets (which depends on whether samba intends to be a domain
772 master or a master browser) in milliseconds.
774 ***************************************************************************/
775 BOOL check_elections(void)
777 struct subnet_record *d;
778 BOOL run_any_election = False;
780 for (d = subnetlist; d; d = d->next)
782 struct work_record *work;
783 for (work = d->workgrouplist; work; work = work->next)
785 run_any_election |= work->RunningElection;
787 if (work->needelection && !work->RunningElection)
789 DEBUG(3,(">>> Starting election on %s %s <<<\n",
790 work->work_group,inet_ntoa(d->bcast_ip)));
791 work->ElectionCount = 0;
792 work->RunningElection = True;
793 work->needelection = False;
797 return run_any_election;