Changed install scripts so they don't have hardcoded values
[Samba.git] / source / nameelect.c
blobbb219415b8ba257b79b1a23d9b5cad14e19fa1c8
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1995
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 Revision History:
23 14 jan 96: lkcl@pires.co.uk
24 added multiple workgroup domain master support
28 #include "includes.h"
30 extern int ClientNMB;
31 extern int ClientDGRAM;
33 extern int DEBUGLEVEL;
34 extern pstring scope;
36 extern pstring myname;
37 extern struct in_addr ipzero;
39 /* machine comment for host announcements */
40 extern pstring ServerComment;
42 /* here are my election parameters */
44 extern time_t StartupTime;
46 extern struct subnet_record *subnetlist;
49 /*******************************************************************
50 occasionally check to see if the master browser is around
51 ******************************************************************/
52 void check_master_browser(void)
54 static time_t lastrun=0;
55 time_t t = time(NULL);
56 struct subnet_record *d;
58 if (!lastrun) lastrun = t;
59 if (t < lastrun + CHECK_TIME_MST_BROWSE * 60)
60 return;
61 lastrun = t;
63 dump_workgroups();
65 for (d = subnetlist; d; d = d->next)
67 struct work_record *work;
69 for (work = d->workgrouplist; work; work = work->next)
71 /* if we are not the browse master of a workgroup, and we can't
72 find a browser on the subnet, do something about it. */
74 if (!AM_MASTER(work))
76 queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
77 work->work_group,0x1d,0,0,
78 True,False,d->bcast_ip);
85 /*******************************************************************
86 what to do if a master browser DOESN't exist
87 ******************************************************************/
88 void browser_gone(char *work_name, struct in_addr ip)
90 struct subnet_record *d = find_subnet(ip);
91 struct work_record *work = find_workgroupstruct(d, work_name, False);
93 if (!work || !d) return;
95 if (strequal(work->work_group, lp_workgroup()) &&
96 ismybcast(d->bcast_ip))
99 DEBUG(2,("Forcing election on %s %s\n",
100 work->work_group,inet_ntoa(d->bcast_ip)));
102 /* we can attempt to become master browser */
103 work->needelection = True;
105 else
107 /* XXXX note: this will delete entries that have been added in by
108 lmhosts as well. a flag to ensure that these are not deleted may
109 be considered */
111 /* workgroup with no master browser is not the default workgroup:
112 it's also not on our subnet. therefore delete it: it can be
113 recreated dynamically */
115 send_election(d, work->work_group, 0, 0, myname);
116 remove_workgroup(d, work);
121 /****************************************************************************
122 send an election packet
123 **************************************************************************/
124 void send_election(struct subnet_record *d, char *group,uint32 criterion,
125 int timeup,char *name)
127 pstring outbuf;
128 char *p;
130 if (!d) return;
132 DEBUG(2,("Sending election to %s for workgroup %s\n",
133 inet_ntoa(d->bcast_ip),group));
135 bzero(outbuf,sizeof(outbuf));
136 p = outbuf;
137 CVAL(p,0) = 8; /* election */
138 p++;
140 CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
141 SIVAL(p,1,criterion);
142 SIVAL(p,5,timeup*1000); /* ms - despite the spec */
143 p += 13;
144 strcpy(p,name);
145 strupper(p);
146 p = skip_string(p,1);
148 send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
149 name,group,0,0x1e,d->bcast_ip,*iface_ip(d->bcast_ip));
153 /****************************************************************************
154 un-register a SELF name that got rejected.
156 if this name happens to be rejected when samba is in the process
157 of becoming a master browser (registering __MSBROWSE__, WORKGROUP(1d)
158 or WORKGROUP(1b)) then we must stop being a master browser. sad.
160 **************************************************************************/
161 void name_unregister_work(struct subnet_record *d, char *name, int name_type)
163 struct work_record *work;
165 remove_netbios_name(d,name,name_type,SELF,ipzero);
167 if (!(work = find_workgroupstruct(d, name, False))) return;
169 if (special_browser_name(name, name_type) ||
170 (AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 &&
171 (name_type == 0x1d || name_type == 0x1b)))
173 int remove_type = 0;
175 if (special_browser_name(name, name_type))
176 remove_type = SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER;
177 if (name_type == 0x1d)
178 remove_type = SV_TYPE_MASTER_BROWSER;
179 if (name_type == 0x1b)
180 remove_type = SV_TYPE_DOMAIN_MASTER;
182 become_nonmaster(d, work, remove_type);
187 /****************************************************************************
188 registers a name.
190 if the name being added is a SELF name, we must additionally check
191 whether to proceed to the next stage in samba becoming a master browser.
193 **************************************************************************/
194 void name_register_work(struct subnet_record *d, char *name, int name_type,
195 int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast)
197 enum name_source source = ismyip(ip) ? SELF : REGISTER;
199 if (source == SELF)
201 struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False);
203 if (work && work->state != MST_NONE)
205 /* samba is in the process of working towards master browser-ness.
206 initiate the next stage.
208 become_master(d, work);
211 add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast);
215 /*******************************************************************
216 become the master browser.
218 this is done in stages. note that this could take a while,
219 particularly on a broadcast subnet, as we have to wait for
220 the implicit registration of each name to be accepted.
222 as each name is successfully registered, become_master() is
223 called again, in order to initiate the next stage. see
224 dead_netbios_entry() - deals with implicit name registration
225 and response_name_reg() - deals with explicit registration
226 with a WINS server.
228 stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1.
229 stage 2: was MST_WON - go to MST_MSB and register WORKGROUP(0x1d)
230 stage 3: was MST_MSB - go to MST_BROWSER and register WORKGROUP(0x1b)
231 stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...)
233 XXXX note: this code still does not cope with the distinction
234 between different types of nodes, particularly between M and P
235 nodes. that comes later.
237 ******************************************************************/
238 void become_master(struct subnet_record *d, struct work_record *work)
240 uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_SERVER_UNIX|0x00400000;
242 if (!work) return;
244 DEBUG(2,("Becoming master for %s (stage %d)",work->work_group,work->state));
246 switch (work->state)
248 case MST_NONE: /* while we were nothing but a server... */
250 work->state = MST_WON; /* election win was successful */
252 work->ElectionCriterion |= 0x5;
254 /* update our server status */
255 work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
256 add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
258 DEBUG(2,("first stage: register ^1^2__MSBROWSE__^2^1\n"));
260 /* add special browser name */
261 add_my_name_entry(d,MSBROWSE ,0x01,NB_ACTIVE|NB_GROUP);
263 break;
265 case MST_WON: /* while nothing had happened except we won an election... */
267 work->state = MST_MSB; /* registering MSBROWSE was successful */
269 /* add server entry on successful registration of MSBROWSE */
270 add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
272 DEBUG(2,("second stage: register as master browser\n"));
274 /* add master name */
275 add_my_name_entry(d,work->work_group,0x1d,NB_ACTIVE );
277 break;
279 case MST_MSB: /* while we were still only registered MSBROWSE state */
281 work->state = MST_BROWSER; /* registering WORKGROUP(1d) was successful */
283 /* update our server status */
284 work->ServerType |= SV_TYPE_MASTER_BROWSER;
285 add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
287 if (d->my_interface && work->serverlist == NULL) /* no servers! */
289 /* ask all servers on our local net to announce to us */
290 announce_request(work, d->bcast_ip);
293 if (lp_domain_master())
295 DEBUG(2,("third stage: register as domain master\n"));
296 /* add domain master name */
297 add_my_name_entry(d,work->work_group,0x1b,NB_ACTIVE );
300 break;
302 case MST_BROWSER: /* while we were still a master browser... */
304 work->state = MST_DOMAIN; /* registering WORKGROUP(1b) was successful */
306 /* update our server status */
307 if (lp_domain_master())
309 work->ServerType |= SV_TYPE_DOMAIN_MASTER;
311 if (lp_domain_logons())
313 work->ServerType |= SV_TYPE_DOMAIN_CTRL;
314 work->ServerType |= SV_TYPE_DOMAIN_MEMBER;
316 DEBUG(2,("fourth stage: samba is now a domain master.\n"));
317 add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
320 break;
322 case MST_DOMAIN:
324 /* nothing else to become, at the moment: we are top-dog. */
325 DEBUG(2,("fifth stage: there isn't one yet!\n"));
326 break;
332 /*******************************************************************
333 unbecome the master browser. initates removal of necessary netbios
334 names, and tells the world that we are no longer a master browser.
335 ******************************************************************/
336 void become_nonmaster(struct subnet_record *d, struct work_record *work,
337 int remove_type)
339 int new_server_type = work->ServerType;
341 DEBUG(2,("Becoming non-master for %s\n",work->work_group));
343 /* can only remove master or domain types with this function */
344 remove_type &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER);
346 /* unbecome a master browser; unbecome a domain master, too :-( */
347 if (remove_type & SV_TYPE_MASTER_BROWSER)
348 remove_type |= SV_TYPE_DOMAIN_MASTER;
350 new_server_type &= ~remove_type;
352 if (!(new_server_type & (SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER)))
354 /* no longer a master browser of any sort */
356 work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
357 work->ElectionCriterion &= ~0x4;
358 work->state = MST_NONE;
360 /* announce ourselves as no longer active as a master browser. */
361 announce_server(d, work, work->work_group, myname, 0, 0);
362 remove_name_entry(d,MSBROWSE ,0x01);
365 work->ServerType = new_server_type;
367 if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
369 if (work->state == MST_DOMAIN)
370 work->state = MST_BROWSER;
371 remove_name_entry(d,work->work_group,0x1b);
375 if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
377 if (work->state >= MST_BROWSER)
378 work->state = MST_NONE;
379 remove_name_entry(d,work->work_group,0x1d);
384 /*******************************************************************
385 run the election
386 ******************************************************************/
387 void run_elections(void)
389 time_t t = time(NULL);
390 static time_t lastime = 0;
392 struct subnet_record *d;
394 /* send election packets once a second */
395 if (lastime && t-lastime <= 0) return;
397 lastime = t;
399 for (d = subnetlist; d; d = d->next)
401 struct work_record *work;
402 for (work = d->workgrouplist; work; work = work->next)
404 if (work->RunningElection)
406 send_election(d,work->work_group, work->ElectionCriterion,
407 t-StartupTime,myname);
409 if (work->ElectionCount++ >= 4)
411 /* I won! now what :-) */
412 DEBUG(2,(">>> Won election on %s %s <<<\n",
413 work->work_group,inet_ntoa(d->bcast_ip)));
415 work->RunningElection = False;
416 work->state = MST_NONE;
418 become_master(d, work);
426 /*******************************************************************
427 work out if I win an election
428 ******************************************************************/
429 static BOOL win_election(struct work_record *work,int version,uint32 criterion,
430 int timeup,char *name)
432 time_t t = time(NULL);
433 uint32 mycriterion;
434 if (version > ELECTION_VERSION) return(False);
435 if (version < ELECTION_VERSION) return(True);
437 mycriterion = work->ElectionCriterion;
439 if (criterion > mycriterion) return(False);
440 if (criterion < mycriterion) return(True);
442 if (timeup > (t - StartupTime)) return(False);
443 if (timeup < (t - StartupTime)) return(True);
445 if (strcasecmp(myname,name) > 0) return(False);
447 return(True);
451 /*******************************************************************
452 process a election packet
454 An election dynamically decides who will be the master.
455 ******************************************************************/
456 void process_election(struct packet_struct *p,char *buf)
458 struct dgram_packet *dgram = &p->packet.dgram;
459 struct in_addr ip = dgram->header.source_ip;
460 struct subnet_record *d = find_subnet(ip);
461 int version = CVAL(buf,0);
462 uint32 criterion = IVAL(buf,1);
463 int timeup = IVAL(buf,5)/1000;
464 char *name = buf+13;
465 struct work_record *work;
467 if (!d) return;
469 name[15] = 0;
471 DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n",
472 name,version,criterion,timeup));
474 if (same_context(dgram)) return;
476 for (work = d->workgrouplist; work; work = work->next)
478 if (listening_name(work, &dgram->dest_name) &&
479 strequal(work->work_group, lp_workgroup()) &&
480 d->my_interface)
482 if (win_election(work, version,criterion,timeup,name))
484 if (!work->RunningElection)
486 work->needelection = True;
487 work->ElectionCount=0;
488 work->state = MST_NONE;
491 else
493 work->needelection = False;
495 if (work->RunningElection)
497 work->RunningElection = False;
498 DEBUG(3,(">>> Lost election on %s %s <<<\n",
499 work->work_group,inet_ntoa(d->bcast_ip)));
501 /* if we are the master then remove our masterly names */
502 if (AM_MASTER(work))
504 become_nonmaster(d, work,
505 SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER);
514 /****************************************************************************
515 checks whether a browser election is to be run on any workgroup
516 ***************************************************************************/
517 BOOL check_elections(void)
519 struct subnet_record *d;
520 BOOL run_any_election = False;
522 for (d = subnetlist; d; d = d->next)
524 struct work_record *work;
525 for (work = d->workgrouplist; work; work = work->next)
527 run_any_election |= work->RunningElection;
529 if (work->needelection && !work->RunningElection)
531 DEBUG(3,(">>> Starting election on %s %s <<<\n",
532 work->work_group,inet_ntoa(d->bcast_ip)));
533 work->ElectionCount = 0;
534 work->RunningElection = True;
535 work->needelection = False;
539 return run_any_election;