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