compile errors. oops.
[Samba.git] / source / nameelect.c
blobe1f36ae2503311bc8add9b489f0a3d3f04aeeeb4
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 ipgrp;
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 for (work = d->workgrouplist; work; work = work->next)
76 if (!AM_MASTER(work))
78 if (lp_preferred_master())
80 /* preferred master - not a master browser. force
81 becoming a master browser, hence the log message.
84 DEBUG(0,("%s preferred master for %s %s - force election\n",
85 timestring(), work->work_group,
86 inet_ntoa(d->bcast_ip)));
88 browser_gone(work->work_group, d->bcast_ip);
90 else
92 /* if we are not the browse master of a workgroup,
93 and we can't find a browser on the subnet, do
94 something about it.
97 queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
98 work->work_group,0x1d,0,0,0,NULL,NULL,
99 True,False,d->bcast_ip,d->bcast_ip);
107 /*******************************************************************
108 what to do if a master browser DOESN't exist
109 ******************************************************************/
110 void browser_gone(char *work_name, struct in_addr ip)
112 struct subnet_record *d = find_subnet(ip);
113 struct work_record *work = find_workgroupstruct(d, work_name, False);
115 /* i don't know about this workgroup, therefore i don't care */
116 if (!work || !d) return;
118 /* don't do election stuff on the WINS subnet */
119 if (ip_equal(d->bcast_ip,ipgrp))
120 return;
122 if (strequal(work->work_group, lp_workgroup()))
125 DEBUG(2,("Forcing election on %s %s\n",
126 work->work_group,inet_ntoa(d->bcast_ip)));
128 /* we can attempt to become master browser */
129 work->needelection = True;
131 else
133 /* local interfaces: force an election */
134 send_election(d, work->work_group, 0, 0, myname);
136 /* only removes workgroup completely on a local interface
137 persistent lmhosts entries on a local interface _will_ be removed).
139 remove_workgroup(d, work,True);
144 /****************************************************************************
145 send an election packet
146 **************************************************************************/
147 void send_election(struct subnet_record *d, char *group,uint32 criterion,
148 int timeup,char *name)
150 pstring outbuf;
151 char *p;
153 if (!d) return;
155 DEBUG(2,("Sending election to %s for workgroup %s\n",
156 inet_ntoa(d->bcast_ip),group));
158 bzero(outbuf,sizeof(outbuf));
159 p = outbuf;
160 CVAL(p,0) = ANN_Election; /* election */
161 p++;
163 CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
164 SIVAL(p,1,criterion);
165 SIVAL(p,5,timeup*1000); /* ms - despite the spec */
166 p += 13;
167 strcpy(p,name);
168 strupper(p);
169 p = skip_string(p,1);
171 send_mailslot_reply(False,BROWSE_MAILSLOT,ClientDGRAM,
172 outbuf,PTR_DIFF(p,outbuf),
173 name,group,0,0x1e,d->bcast_ip,*iface_ip(d->bcast_ip));
177 /****************************************************************************
178 un-register a SELF name that got rejected.
180 if this name happens to be rejected when samba is in the process
181 of becoming a master browser (registering __MSBROWSE__, WORKGROUP(1d)
182 or WORKGROUP(1b)) then we must stop being a master browser. sad.
184 **************************************************************************/
185 void name_unregister_work(struct subnet_record *d, char *name, int name_type)
187 struct work_record *work;
188 int remove_type_local = 0;
189 int remove_type_domain = 0;
190 int remove_type_logon = 0;
192 remove_netbios_name(d,name,name_type,SELF,ipzero);
194 if (!(work = find_workgroupstruct(d, name, False))) return;
196 /* work out what to unbecome, from the name type being removed */
198 if (ms_browser_name(name, name_type))
200 remove_type_local |= SV_TYPE_MASTER_BROWSER;
202 if (AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 &&
203 name_type == 0x1d)
205 remove_type_local |= SV_TYPE_MASTER_BROWSER;
207 if (AM_DOMMST(work) && strequal(name, lp_workgroup()) == 0 &&
208 name_type == 0x1b)
210 remove_type_domain |= SV_TYPE_DOMAIN_MASTER;
212 if (AM_DOMMEM(work) && strequal(name, lp_workgroup()) == 0 &&
213 name_type == 0x1c)
215 remove_type_logon|= SV_TYPE_DOMAIN_MEMBER;
218 if (remove_type_local ) unbecome_local_master (d, work, remove_type_local );
219 if (remove_type_domain) unbecome_domain_master(d, work, remove_type_domain);
220 if (remove_type_logon ) unbecome_logon_server (d, work, remove_type_logon );
224 /****************************************************************************
225 registers a name.
227 if the name being added is a SELF name, we must additionally check
228 whether to proceed to the next stage in samba becoming a master browser.
230 **************************************************************************/
231 void name_register_work(struct subnet_record *d, char *name, int name_type,
232 int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast)
234 enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ?
235 SELF : REGISTER;
237 if (source == SELF)
239 struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False);
241 add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast);
243 if (work)
245 int add_type_local = False;
246 int add_type_domain = False;
247 int add_type_logon = False;
249 /* work out what to become, from the name type being added */
251 if (ms_browser_name(name, name_type))
253 add_type_local = True;
255 if (strequal(name, lp_workgroup()) == 0 && name_type == 0x1d)
257 add_type_local = True;
259 if (strequal(name, lp_workgroup()) == 0 && name_type == 0x1b)
261 add_type_domain = True;
263 if (strequal(name, lp_workgroup()) == 0 && name_type == 0x1c)
265 add_type_logon = True;
268 if (add_type_local ) become_local_master (d, work);
269 if (add_type_domain) become_domain_master(d, work);
270 if (add_type_logon ) become_logon_server (d, work);
276 /*******************************************************************
277 become the local master browser.
279 this is done in stages. note that this could take a while,
280 particularly on a broadcast subnet, as we have to wait for
281 the implicit registration of each name to be accepted.
283 as each name is successfully registered, become_local_master() is
284 called again, in order to initiate the next stage. see
285 dead_netbios_entry() - deals with implicit name registration
286 and response_name_reg() - deals with explicit registration
287 with a WINS server.
289 stage 1: was MST_POTENTIAL - go to MST_POTENTIAL and register ^1^2__MSBROWSE__^2^1.
290 stage 2: was MST_BACK - go to MST_MSB and register WORKGROUP(0x1d)
291 stage 3: was MST_MSB - go to MST_BROWSER and stay there
293 XXXX note: this code still does not cope with the distinction
294 between different types of nodes, particularly between M and P
295 nodes. that comes later.
297 ******************************************************************/
298 void become_local_master(struct subnet_record *d, struct work_record *work)
300 /* domain type must be limited to domain enum + server type. it must
301 not have SV_TYPE_SERVER or anything else with SERVER in it, else
302 clients get confused and start thinking this entry is a server
303 not a workgroup
305 uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT;
307 if (!work || !d) return;
309 DEBUG(2,("Becoming master for %s %s (currently at stage %d)\n",
310 work->work_group,inet_ntoa(d->bcast_ip),work->mst_state));
312 switch (work->mst_state)
314 case MST_POTENTIAL: /* while we were nothing but a server... */
316 DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n"));
317 work->mst_state = MST_BACK; /* ... an election win was successful */
319 work->ElectionCriterion |= 0x5;
321 /* update our server status */
322 work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
323 add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True);
325 /* add special browser name */
326 add_my_name_entry(d,MSBROWSE ,0x01,nb_type|NB_ACTIVE|NB_GROUP);
328 /* DON'T do anything else after calling add_my_name_entry() */
329 break;
332 case MST_BACK: /* while nothing had happened except we won an election... */
334 DEBUG(3,("go to second stage: register as master browser\n"));
335 work->mst_state = MST_MSB; /* ... registering MSBROWSE was successful */
337 /* add server entry on successful registration of MSBROWSE */
338 add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
340 /* add master name */
341 add_my_name_entry(d,work->work_group,0x1d,nb_type|NB_ACTIVE);
343 /* DON'T do anything else after calling add_my_name_entry() */
344 break;
347 case MST_MSB: /* while we were still only registered MSBROWSE state... */
349 DEBUG(3,("2nd stage complete: registered as master browser\n"));
350 work->mst_state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */
352 /* update our server status */
353 work->ServerType |= SV_TYPE_MASTER_BROWSER;
354 add_server_entry(d,work,myname,work->ServerType,0,lp_serverstring(),True);
356 if (work->serverlist == NULL) /* no servers! */
358 /* ask all servers on our local net to announce to us */
359 /* XXXX OOPS! add_server_entry will always add one entry - our own. */
360 announce_request(work, d->bcast_ip);
362 break;
365 case MST_BROWSER:
367 /* don't have to do anything: just report success */
368 DEBUG(3,("3rd stage: become master browser!\n"));
370 break;
376 /*******************************************************************
377 become the domain master browser.
379 this is done in stages. note that this could take a while,
380 particularly on a broadcast subnet, as we have to wait for
381 the implicit registration of each name to be accepted.
383 as each name is successfully registered, become_domain_master() is
384 called again, in order to initiate the next stage. see
385 dead_netbios_entry() - deals with implicit name registration
386 and response_name_reg() - deals with explicit registration
387 with a WINS server.
389 stage 1: was DOMAIN_NONE - go to DOMAIN_MST
391 XXXX note: this code still does not cope with the distinction
392 between different types of nodes, particularly between M and P
393 nodes. that comes later.
395 ******************************************************************/
396 void become_domain_master(struct subnet_record *d, struct work_record *work)
398 /* domain type must be limited to domain enum + server type. it must
399 not have SV_TYPE_SERVER or anything else with SERVER in it, else
400 clients get confused and start thinking this entry is a server
401 not a workgroup
404 if (!work || !d) return;
406 DEBUG(2,("Becoming domain master for %s %s (currently at stage %d)\n",
407 work->work_group,inet_ntoa(d->bcast_ip),work->dom_state));
409 switch (work->dom_state)
411 case DOMAIN_NONE: /* while we were nothing but a server... */
413 if (lp_domain_master())
415 DEBUG(3,("go to first stage: register <1b> name\n"));
416 work->dom_state = DOMAIN_WAIT;
418 /* XXXX the 0x1b is domain master browser name */
419 add_my_name_entry(d, lp_workgroup(),0x1b,nb_type|NB_ACTIVE|NB_GROUP);
421 /* DON'T do anything else after calling add_my_name_entry() */
422 break;
424 else
426 DEBUG(4,("samba not configured as a domain master.\n"));
429 break;
432 case DOMAIN_WAIT:
434 if (lp_domain_master())
436 work->dom_state = DOMAIN_MST; /* ... become domain master */
437 DEBUG(3,("domain first stage: register as domain member\n"));
439 /* update our server status */
440 work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER;
441 add_server_entry(d,work,myname,work->ServerType,0,
442 lp_serverstring(),True);
444 DEBUG(4,("samba is now a domain master\n"));
446 break;
448 else
450 DEBUG(4,("samba not configured as a domain master.\n"));
453 break;
456 case DOMAIN_MST:
458 /* don't have to do anything: just report success */
459 DEBUG(3,("domain second stage: there isn't one!\n"));
460 break;
466 /*******************************************************************
467 become a logon server.
468 ******************************************************************/
469 void become_logon_server(struct subnet_record *d, struct work_record *work)
471 if (!work || !d) return;
473 DEBUG(2,("Becoming logon server for %s %s (currently at stage %d)\n",
474 work->work_group,inet_ntoa(d->bcast_ip),work->log_state));
476 switch (work->log_state)
478 case LOGON_NONE: /* while we were nothing but a server... */
480 if (lp_domain_logons())
482 DEBUG(3,("go to first stage: register <1c> name\n"));
483 work->log_state = LOGON_WAIT;
485 /* XXXX the 0x1c is apparently something to do with domain logons */
486 add_my_name_entry(d, lp_workgroup(),0x1c,nb_type|NB_ACTIVE|NB_GROUP);
488 /* DON'T do anything else after calling add_my_name_entry() */
489 break;
492 DEBUG(4,("samba not configured as a logon master.\n"));
495 break;
498 case LOGON_WAIT:
500 if (lp_domain_logons())
502 work->log_state = LOGON_SRV; /* ... become logon server */
503 DEBUG(3,("logon second stage: register \n"));
505 /* update our server status */
506 work->ServerType |= SV_TYPE_NT|SV_TYPE_DOMAIN_MEMBER;
507 add_server_entry(d,work,myname,work->ServerType,0,
508 lp_serverstring(),True);
510 /* DON'T do anything else after calling add_my_name_entry() */
511 break;
513 else
515 DEBUG(4,("samba not configured as a logon server.\n"));
518 break;
521 case LOGON_SRV:
523 DEBUG(3,("logon third stage: there isn't one!\n"));
524 break;
531 /*******************************************************************
532 unbecome the local master browser. initates removal of necessary netbios
533 names, and tells the world that we are no longer a master browser.
535 XXXX this _should_ be used to demote to a backup master browser, without
536 going straight to non-master browser. another time.
538 ******************************************************************/
539 void unbecome_local_master(struct subnet_record *d, struct work_record *work,
540 int remove_type)
542 int new_server_type = work->ServerType;
544 /* can only remove master types with this function */
545 remove_type &= SV_TYPE_MASTER_BROWSER;
547 new_server_type &= ~remove_type;
549 if (remove_type)
551 DEBUG(2,("Becoming local non-master for %s\n",work->work_group));
553 /* no longer a master browser of any sort */
555 work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
556 work->ElectionCriterion &= ~0x4;
557 work->mst_state = MST_POTENTIAL;
559 /* announce ourselves as no longer active as a master browser. */
560 announce_server(d, work, work->work_group, myname, 0, 0);
561 remove_name_entry(d,MSBROWSE ,0x01);
562 remove_name_entry(d,work->work_group,0x1d);
567 /*******************************************************************
568 unbecome the domain master browser. initates removal of necessary netbios
569 names, and tells the world that we are no longer a domain browser.
570 ******************************************************************/
571 void unbecome_domain_master(struct subnet_record *d, struct work_record *work,
572 int remove_type)
574 int new_server_type = work->ServerType;
576 DEBUG(2,("Becoming domain non-master for %s\n",work->work_group));
578 /* can only remove master or domain types with this function */
579 remove_type &= SV_TYPE_DOMAIN_MASTER;
581 new_server_type &= ~remove_type;
583 if (remove_type)
585 /* no longer a domain master browser of any sort */
587 work->dom_state = DOMAIN_NONE;
589 /* announce ourselves as no longer active as a master browser. */
590 announce_server(d, work, work->work_group, myname, 0, 0);
591 remove_name_entry(d,work->work_group,0x1b);
596 /*******************************************************************
597 unbecome the logon server. initates removal of necessary netbios
598 names, and tells the world that we are no longer a logon server.
599 ******************************************************************/
600 void unbecome_logon_server(struct subnet_record *d, struct work_record *work,
601 int remove_type)
603 int new_server_type = work->ServerType;
605 DEBUG(2,("Becoming logon non-server for %s\n",work->work_group));
607 /* can only remove master or domain types with this function */
608 remove_type &= SV_TYPE_DOMAIN_MEMBER;
610 new_server_type &= ~remove_type;
612 if (remove_type)
614 /* no longer a master browser of any sort */
616 work->log_state = LOGON_NONE;
618 /* announce ourselves as no longer active as a master browser. */
619 announce_server(d, work, work->work_group, myname, 0, 0);
620 remove_name_entry(d,work->work_group,0x1c);
625 /*******************************************************************
626 run the election
627 ******************************************************************/
628 void run_elections(time_t t)
630 static time_t lastime = 0;
632 struct subnet_record *d;
634 /* send election packets once a second */
635 if (lastime && t-lastime <= 0) return;
637 lastime = t;
639 for (d = subnetlist; d; d = d->next)
641 struct work_record *work;
642 for (work = d->workgrouplist; work; work = work->next)
644 if (work->RunningElection)
646 send_election(d,work->work_group, work->ElectionCriterion,
647 t-StartupTime,myname);
649 if (work->ElectionCount++ >= 4)
651 /* I won! now what :-) */
652 DEBUG(2,(">>> Won election on %s %s <<<\n",
653 work->work_group,inet_ntoa(d->bcast_ip)));
655 work->RunningElection = False;
656 work->mst_state = MST_POTENTIAL;
658 become_local_master(d, work);
666 /*******************************************************************
667 work out if I win an election
668 ******************************************************************/
669 static BOOL win_election(struct work_record *work,int version,uint32 criterion,
670 int timeup,char *name)
672 int mytimeup = time(NULL) - StartupTime;
673 uint32 mycriterion = work->ElectionCriterion;
675 DEBUG(4,("election comparison: %x:%x %x:%x %d:%d %s:%s\n",
676 version,ELECTION_VERSION,
677 criterion,mycriterion,
678 timeup,mytimeup,
679 name,myname));
681 if (version > ELECTION_VERSION) return(False);
682 if (version < ELECTION_VERSION) return(True);
684 if (criterion > mycriterion) return(False);
685 if (criterion < mycriterion) return(True);
687 if (timeup > mytimeup) return(False);
688 if (timeup < mytimeup) return(True);
690 if (strcasecmp(myname,name) > 0) return(False);
692 return(True);
696 /*******************************************************************
697 process a election packet
699 An election dynamically decides who will be the master.
700 ******************************************************************/
701 void process_election(struct packet_struct *p,char *buf)
703 struct dgram_packet *dgram = &p->packet.dgram;
704 struct in_addr ip = dgram->header.source_ip;
705 struct subnet_record *d = find_subnet(ip);
706 int version = CVAL(buf,0);
707 uint32 criterion = IVAL(buf,1);
708 int timeup = IVAL(buf,5)/1000;
709 char *name = buf+13;
710 struct work_record *work;
712 if (!d) return;
714 if (ip_equal(d->bcast_ip,ipgrp)) {
715 DEBUG(3,("Unexpected election request from %s %s on WINS net\n",
716 name, inet_ntoa(p->ip)));
717 return;
720 name[15] = 0;
722 DEBUG(3,("Election request from %s %s vers=%d criterion=%08x timeup=%d\n",
723 name,inet_ntoa(p->ip),version,criterion,timeup));
725 if (same_context(dgram)) return;
727 for (work = d->workgrouplist; work; work = work->next)
729 if (!strequal(work->work_group, lp_workgroup()))
730 continue;
732 if (win_election(work, version,criterion,timeup,name)) {
733 if (!work->RunningElection) {
734 work->needelection = True;
735 work->ElectionCount=0;
736 work->mst_state = MST_POTENTIAL;
738 } else {
739 work->needelection = False;
741 if (work->RunningElection || AM_MASTER(work)) {
742 work->RunningElection = False;
743 DEBUG(3,(">>> Lost election on %s %s <<<\n",
744 work->work_group,inet_ntoa(d->bcast_ip)));
745 if (AM_MASTER(work))
746 unbecome_local_master(d, work, SV_TYPE_MASTER_BROWSER);
753 /****************************************************************************
754 checks whether a browser election is to be run on any workgroup
756 this function really ought to return the time between election
757 packets (which depends on whether samba intends to be a domain
758 master or a master browser) in milliseconds.
760 ***************************************************************************/
761 BOOL check_elections(void)
763 struct subnet_record *d;
764 BOOL run_any_election = False;
766 for (d = subnetlist; d; d = d->next)
768 struct work_record *work;
769 for (work = d->workgrouplist; work; work = work->next)
771 run_any_election |= work->RunningElection;
773 if (work->needelection && !work->RunningElection)
775 DEBUG(3,(">>> Starting election on %s %s <<<\n",
776 work->work_group,inet_ntoa(d->bcast_ip)));
777 work->ElectionCount = 0;
778 work->RunningElection = True;
779 work->needelection = False;
783 return run_any_election;