2b0fa5c0dd05725e6bc2fea5fd141239f3ee2849
[samba.git] / source3 / nameelect.c
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
6    
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.
11    
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.
16    
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.
20    
21    Module name: nameelect.c
22
23    Revision History:
24
25    14 jan 96: lkcl@pires.co.uk
26    added multiple workgroup domain master support
27
28    04 jul 96: lkcl@pires.co.uk
29    added system to become a master browser by stages.
30
31
32 */
33
34 #include "includes.h"
35
36 extern int ClientNMB;
37 extern int ClientDGRAM;
38
39 extern int DEBUGLEVEL;
40 extern pstring scope;
41
42 extern pstring myname;
43 extern struct in_addr ipzero;
44 extern struct in_addr ipgrp;
45
46 /* machine comment for host announcements */
47 extern  pstring ServerComment;
48
49 /* here are my election parameters */
50
51 extern time_t StartupTime;
52
53 extern struct subnet_record *subnetlist;
54
55
56 /*******************************************************************
57   occasionally check to see if the master browser is around
58   ******************************************************************/
59 void check_master_browser(void)
60 {
61   static time_t lastrun=0;
62   time_t t = time(NULL);
63   struct subnet_record *d;
64
65   if (!lastrun) lastrun = t;
66   if (t < lastrun + CHECK_TIME_MST_BROWSE * 60)
67     return;
68   lastrun = t;
69
70   dump_workgroups();
71
72   for (d = subnetlist; d; d = d->next)
73     {
74       struct work_record *work;
75
76       for (work = d->workgrouplist; work; work = work->next)
77         {
78           /* if we are not the browse master of a workgroup, and we can't
79              find a browser on the subnet, do something about it. */
80
81           if (!AM_MASTER(work))
82             {
83               queue_netbios_packet(d,ClientNMB,NMB_QUERY,NAME_QUERY_MST_CHK,
84                                    work->work_group,0x1d,0,0,
85                                    True,False,d->bcast_ip,d->bcast_ip);
86             }
87         }
88     }
89 }
90
91
92 /*******************************************************************
93   what to do if a master browser DOESN't exist
94   ******************************************************************/
95 void browser_gone(char *work_name, struct in_addr ip)
96 {
97   struct subnet_record *d = find_subnet(ip);
98   struct work_record *work = find_workgroupstruct(d, work_name, False);
99
100   /* i don't know about this workgroup, therefore i don't care */
101   if (!work || !d) return;
102  
103   if (strequal(work->work_group, lp_workgroup()) && d->my_interface)
104   {
105
106       DEBUG(2,("Forcing election on %s %s\n",
107                work->work_group,inet_ntoa(d->bcast_ip)));
108
109       /* we can attempt to become master browser */
110       work->needelection = True;
111   }
112   else
113   {
114      /* local interfaces: force an election */
115      if (d->my_interface)
116        send_election(d, work->work_group, 0, 0, myname);
117
118      /* only removes workgroup completely on a local interface or
119         if there are no server entries on the remote interface.
120         (persistent lmhost entries on a remote interface will stop
121         the workgroup being removed. persistent lmhosts entries on
122         a local interface _will_ be removed).
123       */
124      remove_workgroup(d, work, d->my_interface);      
125   }
126 }
127
128
129 /****************************************************************************
130   send an election packet
131   **************************************************************************/
132 void send_election(struct subnet_record *d, char *group,uint32 criterion,
133                    int timeup,char *name)
134 {
135   pstring outbuf;
136   char *p;
137
138   if (!d) return;
139   
140   DEBUG(2,("Sending election to %s for workgroup %s\n",
141            inet_ntoa(d->bcast_ip),group));         
142
143   bzero(outbuf,sizeof(outbuf));
144   p = outbuf;
145   CVAL(p,0) = ANN_Election; /* election */
146   p++;
147
148   CVAL(p,0) = (criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION;
149   SIVAL(p,1,criterion);
150   SIVAL(p,5,timeup*1000); /* ms - despite the spec */
151   p += 13;
152   strcpy(p,name);
153   strupper(p);
154   p = skip_string(p,1);
155   
156   send_mailslot_reply(BROWSE_MAILSLOT,ClientDGRAM,outbuf,PTR_DIFF(p,outbuf),
157                       name,group,0,0x1e,d->bcast_ip,*iface_ip(d->bcast_ip));
158 }
159
160
161 /****************************************************************************
162   un-register a SELF name that got rejected.
163
164   if this name happens to be rejected when samba is in the process
165   of becoming a master browser (registering __MSBROWSE__, WORKGROUP(1d)
166   or WORKGROUP(1b)) then we must stop being a master browser. sad.
167
168   **************************************************************************/
169 void name_unregister_work(struct subnet_record *d, char *name, int name_type)
170 {
171     struct work_record *work;
172
173     remove_netbios_name(d,name,name_type,SELF,ipzero);
174
175     if (!(work = find_workgroupstruct(d, name, False))) return;
176
177     if (ms_browser_name(name, name_type) ||
178         (AM_MASTER(work) && strequal(name, lp_workgroup()) == 0 &&
179          (name_type == 0x1d || name_type == 0x1b)))
180     {
181       int remove_type = 0;
182
183       if (ms_browser_name(name, name_type))
184         remove_type = SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER;
185       if (name_type == 0x1d)
186         remove_type = SV_TYPE_MASTER_BROWSER;
187       if (name_type == 0x1b)
188         remove_type = SV_TYPE_DOMAIN_MASTER;
189                         
190       become_nonmaster(d, work, remove_type);
191     }
192 }
193
194
195 /****************************************************************************
196   registers a name.
197
198   if the name being added is a SELF name, we must additionally check
199   whether to proceed to the next stage in samba becoming a master browser.
200
201   **************************************************************************/
202 void name_register_work(struct subnet_record *d, char *name, int name_type,
203                                 int nb_flags, time_t ttl, struct in_addr ip, BOOL bcast)
204 {
205   enum name_source source = (ismyip(ip) || ip_equal(ip, ipzero)) ?
206                                                                 SELF : REGISTER;
207
208   if (source == SELF)
209   {
210     struct work_record *work = find_workgroupstruct(d, lp_workgroup(), False);
211
212     add_netbios_entry(d,name,name_type,nb_flags,ttl,source,ip,True,!bcast);
213
214     if (work)
215     {
216       if (work->state != MST_NONE)
217       {
218         /* samba is in the process of working towards master browser-ness.
219            initiate the next stage.
220          */
221         become_master(d, work);
222         return;
223       }
224     }
225   }
226 }
227
228
229 /*******************************************************************
230   become the master browser.
231
232   this is done in stages. note that this could take a while, 
233   particularly on a broadcast subnet, as we have to wait for
234   the implicit registration of each name to be accepted.
235
236   as each name is successfully registered, become_master() is
237   called again, in order to initiate the next stage. see
238   dead_netbios_entry() - deals with implicit name registration
239   and response_name_reg() - deals with explicit registration
240   with a WINS server.
241
242   stage 1: was MST_NONE - go to MST_NONE and register ^1^2__MSBROWSE__^2^1.
243   stage 2: was MST_WON  - go to MST_MSB  and register WORKGROUP(0x1d)
244   stage 3: was MST_MSB  - go to MST_BROWSER and register WORKGROUP(0x1b)
245   stage 4: was MST_BROWSER - go to MST_DOMAIN (do not pass GO, do not...)
246
247   XXXX note: this code still does not cope with the distinction
248   between different types of nodes, particularly between M and P
249   nodes. that comes later.
250
251   ******************************************************************/
252 void become_master(struct subnet_record *d, struct work_record *work)
253 {
254   uint32 domain_type = SV_TYPE_DOMAIN_ENUM|SV_TYPE_SERVER_UNIX|0x00400000;
255
256   if (!work) return;
257   
258   DEBUG(2,("Becoming master for %s %s (currently at stage %d)\n",
259                                         work->work_group,inet_ntoa(d->bcast_ip),work->state));
260   
261   switch (work->state)
262   {
263     case MST_NONE: /* while we were nothing but a server... */
264     {
265       DEBUG(3,("go to first stage: register ^1^2__MSBROWSE__^2^1\n"));
266       work->state = MST_WON; /* ... an election win was successful */
267
268       work->ElectionCriterion |= 0x5;
269
270       /* update our server status */
271       work->ServerType &= ~SV_TYPE_POTENTIAL_BROWSER;
272       add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
273
274       /* add special browser name */
275       add_my_name_entry(d,MSBROWSE        ,0x01,NB_ACTIVE|NB_GROUP);
276
277       /* DON'T do anything else after calling add_my_name_entry() */
278       return;
279     }
280     case MST_WON: /* while nothing had happened except we won an election... */
281     {
282       DEBUG(3,("go to second stage: register as master browser\n"));
283       work->state = MST_MSB; /* ... registering MSBROWSE was successful */
284
285       /* add server entry on successful registration of MSBROWSE */
286       add_server_entry(d,work,work->work_group,domain_type,0,myname,True);
287
288       /* add master name */
289       add_my_name_entry(d,work->work_group,0x1d,NB_ACTIVE         );
290   
291       /* DON'T do anything else after calling add_my_name_entry() */
292       return;
293     }
294     case MST_MSB: /* while we were still only registered MSBROWSE state... */
295     {
296       DEBUG(3,("2nd stage complete: registered as master browser\n"));
297       work->state = MST_BROWSER; /* ... registering WORKGROUP(1d) succeeded */
298
299       /* update our server status */
300       work->ServerType |= SV_TYPE_MASTER_BROWSER;
301       add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
302
303       if (d->my_interface && work->serverlist == NULL) /* no servers! */
304       {
305         /* ask all servers on our local net to announce to us */
306         announce_request(work, d->bcast_ip);
307       }
308       break;
309    }
310
311    case MST_BROWSER:
312    {
313       /* don't have to do anything: just report success */
314       DEBUG(3,("3rd stage: become master browser!\n"));
315
316       break;
317    }
318
319    case MST_DOMAIN_NONE:
320    {
321       if (lp_domain_master())
322       {
323         work->state = MST_DOMAIN_MEM; /* ... become domain member */
324         DEBUG(3,("domain first stage: register as domain member\n"));
325
326         /* add domain member name */
327         add_my_name_entry(d,work->work_group,0x1e,NB_ACTIVE         );
328
329         /* DON'T do anything else after calling add_my_name_entry() */
330         return;
331       }
332       else
333       {
334         DEBUG(4,("samba not configured as a domain master.\n"));
335       }
336   
337       break;
338    }
339
340    case MST_DOMAIN_MEM:
341    {
342       if (lp_domain_master())
343       {
344         work->state = MST_DOMAIN_TST; /* ... possibly become domain master */
345         DEBUG(3,("domain second stage: register as domain master\n"));
346
347         if (lp_domain_logons())
348             {
349           work->ServerType |= SV_TYPE_DOMAIN_MEMBER;
350           add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
351         }
352
353         /* add domain master name */
354         add_my_name_entry(d,work->work_group,0x1b,NB_ACTIVE         );
355
356         /* DON'T do anything else after calling add_my_name_entry() */
357         return;
358       }
359       else
360       {
361         DEBUG(4,("samba not configured as a domain master.\n"));
362       }
363   
364       break;
365     }
366
367     case MST_DOMAIN_TST: /* while we were still a master browser... */
368     {
369       /* update our server status */
370       if (lp_domain_master())
371       {
372         struct subnet_record *d1;
373                 uint32 update_type = 0;
374
375         DEBUG(3,("domain third stage: samba is now a domain master.\n"));
376         work->state = MST_DOMAIN; /* ... registering WORKGROUP(1b) succeeded */
377
378         update_type |= SV_TYPE_DOMAIN_MASTER;
379       
380         if (lp_domain_logons())
381             {
382               update_type |= SV_TYPE_DOMAIN_CTRL;
383             }
384
385                 work->ServerType |= update_type;
386         add_server_entry(d,work,myname,work->ServerType,0,ServerComment,True);
387
388                 for (d1 = subnetlist; d1; d1 = d1->next)
389                 {
390                 struct work_record *w;
391                         if (ip_equal(d1->bcast_ip, d->bcast_ip)) continue;
392
393                 for (w = d1->workgrouplist; w; w = w->next)
394                         {
395                                 struct server_record *s = find_server(w, myname);
396                                 if (strequal(w->work_group, work->work_group))
397                                 {
398                                         w->ServerType |= update_type;
399                                 }
400                                 if (s)
401                                 {
402                                         s->serv.type |= update_type;
403                                         DEBUG(4,("found server %s on %s: update to %8x\n",
404                                                                         s->serv.name, inet_ntoa(d1->bcast_ip),
405                                                                         s->serv.type));
406                                 }
407                         }
408                 }
409       }
410   
411       break;
412     }
413
414     case MST_DOMAIN:
415     {
416       /* don't have to do anything: just report success */
417       DEBUG(3,("fifth stage: there isn't one yet!\n"));
418       break;
419     }
420   }
421 }
422
423
424 /*******************************************************************
425   unbecome the master browser. initates removal of necessary netbios 
426   names, and tells the world that we are no longer a master browser.
427   ******************************************************************/
428 void become_nonmaster(struct subnet_record *d, struct work_record *work,
429                                 int remove_type)
430 {
431   int new_server_type = work->ServerType;
432
433   DEBUG(2,("Becoming non-master for %s\n",work->work_group));
434   
435   /* can only remove master or domain types with this function */
436   remove_type &= ~(SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER);
437
438   /* unbecome a master browser; unbecome a domain master, too :-( */
439   if (remove_type & SV_TYPE_MASTER_BROWSER)
440     remove_type |= SV_TYPE_DOMAIN_MASTER;
441
442   new_server_type &= ~remove_type;
443
444   if (!(new_server_type & (SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER)))
445   {
446     /* no longer a master browser of any sort */
447
448         work->ServerType |= SV_TYPE_POTENTIAL_BROWSER;
449     work->ElectionCriterion &= ~0x4;
450     work->state = MST_NONE;
451
452         /* announce ourselves as no longer active as a master browser. */
453     announce_server(d, work, work->work_group, myname, 0, 0);
454     remove_name_entry(d,MSBROWSE        ,0x01);
455   }
456   
457   work->ServerType = new_server_type;
458
459   if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
460   {
461     if (work->state == MST_DOMAIN)
462       work->state = MST_BROWSER;
463     remove_name_entry(d,work->work_group,0x1b);
464     
465   }
466
467   if (!(work->ServerType & SV_TYPE_DOMAIN_MASTER))
468   {
469     if (work->state >= MST_BROWSER)
470       work->state = MST_NONE;
471     remove_name_entry(d,work->work_group,0x1d);
472   }
473 }
474
475
476 /*******************************************************************
477   run the election
478   ******************************************************************/
479 void run_elections(void)
480 {
481   time_t t = time(NULL);
482   static time_t lastime = 0;
483   
484   struct subnet_record *d;
485   
486   /* send election packets once a second */
487   if (lastime && t-lastime <= 0) return;
488   
489   lastime = t;
490   
491   for (d = subnetlist; d; d = d->next)
492   {
493     struct work_record *work;
494     for (work = d->workgrouplist; work; work = work->next)
495         {
496           if (work->RunningElection)
497           {
498             send_election(d,work->work_group, work->ElectionCriterion,
499                             t-StartupTime,myname);
500               
501             if (work->ElectionCount++ >= 4)
502                 {
503                   /* I won! now what :-) */
504                   DEBUG(2,(">>> Won election on %s %s <<<\n",
505                            work->work_group,inet_ntoa(d->bcast_ip)));
506                   
507                   work->RunningElection = False;
508           work->state = MST_NONE;
509
510                   become_master(d, work);
511                 }
512           }
513         }
514   }
515 }
516
517
518 /*******************************************************************
519   work out if I win an election
520   ******************************************************************/
521 static BOOL win_election(struct work_record *work,int version,uint32 criterion,
522                          int timeup,char *name)
523 {  
524   time_t t = time(NULL);
525   uint32 mycriterion;
526   if (version > ELECTION_VERSION) return(False);
527   if (version < ELECTION_VERSION) return(True);
528   
529   mycriterion = work->ElectionCriterion;
530
531   if (criterion > mycriterion) return(False);
532   if (criterion < mycriterion) return(True);
533
534   if (timeup > (t - StartupTime)) return(False);
535   if (timeup < (t - StartupTime)) return(True);
536
537   if (strcasecmp(myname,name) > 0) return(False);
538   
539   return(True);
540 }
541
542
543 /*******************************************************************
544   process a election packet
545
546   An election dynamically decides who will be the master. 
547   ******************************************************************/
548 void process_election(struct packet_struct *p,char *buf)
549 {
550   struct dgram_packet *dgram = &p->packet.dgram;
551   struct in_addr ip = dgram->header.source_ip;
552   struct subnet_record *d = find_subnet(ip);
553   int version = CVAL(buf,0);
554   uint32 criterion = IVAL(buf,1);
555   int timeup = IVAL(buf,5)/1000;
556   char *name = buf+13;
557   struct work_record *work;
558
559   if (!d) return;
560   
561   name[15] = 0;  
562
563   DEBUG(3,("Election request from %s vers=%d criterion=%08x timeup=%d\n",
564            name,version,criterion,timeup));
565   
566   if (same_context(dgram)) return;
567   
568   for (work = d->workgrouplist; work; work = work->next)
569     {
570       if (listening_name(work, &dgram->dest_name) && 
571           strequal(work->work_group, lp_workgroup()) &&
572           d->my_interface)
573         {
574           if (win_election(work, version,criterion,timeup,name))
575             {
576               if (!work->RunningElection)
577                 {
578                   work->needelection = True;
579                   work->ElectionCount=0;
580           work->state = MST_NONE;
581                 }
582             }
583           else
584             {
585               work->needelection = False;
586               
587               if (work->RunningElection)
588                 {
589                   work->RunningElection = False;
590                   DEBUG(3,(">>> Lost election on %s %s <<<\n",
591                            work->work_group,inet_ntoa(d->bcast_ip)));
592                   
593                   /* if we are the master then remove our masterly names */
594                   if (AM_MASTER(work))
595                   {
596                       become_nonmaster(d, work,
597                                         SV_TYPE_MASTER_BROWSER|SV_TYPE_DOMAIN_MASTER);
598                   }
599                 }
600             }
601         }
602     }
603 }
604
605
606 /****************************************************************************
607   checks whether a browser election is to be run on any workgroup
608
609   this function really ought to return the time between election
610   packets (which depends on whether samba intends to be a domain
611   master or a master browser) in milliseconds.
612
613   ***************************************************************************/
614 BOOL check_elections(void)
615 {
616   struct subnet_record *d;
617   BOOL run_any_election = False;
618
619   for (d = subnetlist; d; d = d->next)
620     {
621       struct work_record *work;
622       for (work = d->workgrouplist; work; work = work->next)
623         {
624           run_any_election |= work->RunningElection;
625           
626           if (work->needelection && !work->RunningElection)
627             {
628               DEBUG(3,(">>> Starting election on %s %s <<<\n",
629                        work->work_group,inet_ntoa(d->bcast_ip)));
630               work->ElectionCount = 0;
631               work->RunningElection = True;
632               work->needelection = False;
633             }
634         }
635     }
636   return run_any_election;
637 }
638