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