31c67ae7f3f46d87289cc8eaf582a6a245157176
[kai/samba.git] / source3 / nmbd / nmbd_become_lmb.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-1998
6    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
7    Copyright (C) Jeremy Allison 1994-1998
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22    
23 */
24
25 #include "includes.h"
26
27 extern int DEBUGLEVEL;
28 extern pstring global_myname;
29
30 extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
31
32 /*******************************************************************
33  Utility function to add a name to the unicast subnet, or add in
34  our IP address if it already exists.
35 ******************************************************************/
36
37 void insert_permanent_name_into_unicast( struct subnet_record *subrec, 
38                                                 struct nmb_name *nmbname, uint16 nb_type )
39 {
40   struct name_record *namerec;
41
42   if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL)
43   {
44     /* The name needs to be created on the unicast subnet. */
45     (void)add_name_to_subnet( unicast_subnet, nmbname->name,
46                               nmbname->name_type, nb_type,
47                               PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
48   }
49   else
50   {
51     /* The name already exists on the unicast subnet. Add our local
52        IP for the given broadcast subnet to the name. */
53     add_ip_to_name_record( namerec, subrec->myip);
54   }
55 }
56
57 /*******************************************************************
58  Utility function to remove a name from the unicast subnet.
59 ******************************************************************/
60
61 static void remove_permanent_name_from_unicast( struct subnet_record *subrec,
62                                                 struct nmb_name *nmbname )
63 {
64   struct name_record *namerec;
65
66   if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) != NULL)
67   {
68     /* Remove this broadcast subnet IP address from the name. */
69     remove_ip_from_name_record( namerec, subrec->myip);
70     if(namerec->data.num_ips == 0)
71       remove_name_from_namelist( unicast_subnet, namerec);
72   }
73 }
74
75 /*******************************************************************
76  Utility function always called to set our workgroup and server
77  state back to potential browser, or none.
78 ******************************************************************/
79
80 static void reset_workgroup_state( struct subnet_record *subrec, char *workgroup_name,
81                                    BOOL force_new_election )
82 {
83   struct work_record *work;
84   struct server_record *servrec;
85   struct nmb_name nmbname;
86
87   if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL)
88   {
89     DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
90 subnet %s.\n", workgroup_name, subrec->subnet_name ));
91     return;
92   }
93
94   if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
95   {
96     DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
97 in workgroup %s on subnet %s\n",
98        global_myname, work->work_group, subrec->subnet_name));
99     work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
100     return;
101   }
102
103   /* Update our server status - remove any master flag and replace
104    it with the potential browser flag. */
105   servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
106   servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
107
108   /* Tell the namelist writer to write out a change. */
109   subrec->work_changed = True;
110
111   /* Reset our election flags. */
112   work->ElectionCriterion &= ~0x4;
113
114   work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
115
116   /* Forget who the local master browser was for
117      this workgroup. */
118
119   set_workgroup_local_master_browser_name( work, "");
120
121   /*
122    * Ensure the IP address of this subnet is not registered as one
123    * of the IP addresses of the WORKGROUP<1d> name on the unicast
124    * subnet. This undoes what we did below when we became a local
125    * master browser.
126    */
127
128   make_nmb_name(&nmbname, work->work_group, 0x1d);
129
130   remove_permanent_name_from_unicast( subrec, &nmbname);
131
132   if(force_new_election)
133     work->needelection = True;
134 }
135
136 /*******************************************************************
137   Unbecome the local master browser name release success function.
138 ******************************************************************/
139
140 static void unbecome_local_master_success(struct subnet_record *subrec,
141                              struct userdata_struct *userdata,
142                              struct nmb_name *released_name,
143                              struct in_addr released_ip)
144
145   BOOL force_new_election = False;
146
147   memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
148
149   DEBUG(3,("unbecome_local_master_success: released name %s.\n",
150              nmb_namestr(released_name)));
151
152   /* Now reset the workgroup and server state. */
153   reset_workgroup_state( subrec, released_name->name, force_new_election );
154
155   if( DEBUGLVL( 0 ) )
156   {
157     dbgtext( "*****\n\n" );
158     dbgtext( "Samba name server %s ", global_myname );
159     dbgtext( "has stopped being a local master browser " );
160     dbgtext( "for workgroup %s ", released_name->name );
161     dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
162   }
163
164 }
165
166 /*******************************************************************
167   Unbecome the local master browser name release fail function.
168 ******************************************************************/
169
170 static void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec,
171                        struct nmb_name *fail_name)
172 {
173   struct name_record *namerec;
174   struct userdata_struct *userdata = rrec->userdata;
175   BOOL force_new_election = False;
176
177   memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
178
179   DEBUG(0,("unbecome_local_master_fail: failed to release name %s. \
180 Removing from namelist anyway.\n", nmb_namestr(fail_name)));
181
182   /* Do it anyway. */
183   namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
184   if(namerec)
185     remove_name_from_namelist(subrec, namerec);
186
187   /* Now reset the workgroup and server state. */
188   reset_workgroup_state( subrec, fail_name->name, force_new_election );
189
190   if( DEBUGLVL( 0 ) )
191   {
192     dbgtext( "*****\n\n" );
193     dbgtext( "Samba name server %s ", global_myname );
194     dbgtext( "has stopped being a local master browser " );
195     dbgtext( "for workgroup %s ", fail_name->name );
196     dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
197   }
198 }
199
200 /*******************************************************************
201  Utility function to remove the WORKGROUP<1d> name.
202 ******************************************************************/
203
204 static void release_1d_name( struct subnet_record *subrec, char *workgroup_name,
205                              BOOL force_new_election)
206 {
207   struct nmb_name nmbname;
208   struct name_record *namerec;
209
210   make_nmb_name(&nmbname, workgroup_name, 0x1d);
211   if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
212   {
213     struct userdata_struct *userdata;
214     int size = sizeof(struct userdata_struct) + sizeof(BOOL);
215
216     if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
217     {
218       DEBUG(0,("release_1d_name: malloc fail.\n"));
219       return;
220     }
221
222     userdata->copy_fn = NULL;
223     userdata->free_fn = NULL;
224     userdata->userdata_len = sizeof(BOOL);
225     memcpy((char *)userdata->data, &force_new_election, sizeof(BOOL));
226
227     release_name(subrec, namerec,
228                  unbecome_local_master_success,
229                  unbecome_local_master_fail,
230                  userdata);
231
232     zero_free(userdata, size);
233   }
234 }
235
236 /*******************************************************************
237  Unbecome the local master browser MSBROWSE name release success function.
238 ******************************************************************/
239
240 static void release_msbrowse_name_success(struct subnet_record *subrec,
241                       struct userdata_struct *userdata,
242                       struct nmb_name *released_name,
243                       struct in_addr released_ip)
244 {
245   DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
246            nmb_namestr(released_name), subrec->subnet_name ));
247
248   /* Remove the permanent MSBROWSE name added into the unicast subnet. */
249   remove_permanent_name_from_unicast( subrec, released_name);
250 }
251
252 /*******************************************************************
253  Unbecome the local master browser MSBROWSE name release fail function.
254 ******************************************************************/
255
256 static void release_msbrowse_name_fail( struct subnet_record *subrec, 
257                        struct response_record *rrec,
258                        struct nmb_name *fail_name)
259 {
260   struct name_record *namerec;
261
262   DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
263            nmb_namestr(fail_name), subrec->subnet_name ));
264
265   /* Release the name anyway. */
266   namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
267   if(namerec)
268     remove_name_from_namelist(subrec, namerec);
269
270   /* Remove the permanent MSBROWSE name added into the unicast subnet. */
271   remove_permanent_name_from_unicast( subrec, fail_name);
272 }
273
274 /*******************************************************************
275   Unbecome the local master browser. If force_new_election is true, restart
276   the election process after we've unbecome the local master.
277 ******************************************************************/
278
279 void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work,
280                                    BOOL force_new_election)
281 {
282   struct name_record *namerec;
283   struct nmb_name nmbname;
284
285   /* Sanity check. */
286
287   DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \
288 on subnet %s\n",work->work_group, subrec->subnet_name));
289   
290   if(find_server_in_workgroup( work, global_myname) == NULL)
291   {
292     DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
293 in workgroup %s on subnet %s\n",
294        global_myname, work->work_group, subrec->subnet_name));
295     work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
296     return;
297   }
298   
299   /* Set the state to unbecoming. */
300   work->mst_state = MST_UNBECOMING_MASTER;
301
302   /*
303    * Release the WORKGROUP<1d> name asap to allow another machine to
304    * claim it.
305    */
306
307   release_1d_name( subrec, work->work_group, force_new_election);
308
309   /* Deregister any browser names we may have. */
310   make_nmb_name(&nmbname, MSBROWSE, 0x1);
311   if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
312   {
313     release_name(subrec, namerec,
314                  release_msbrowse_name_success,
315                  release_msbrowse_name_fail,
316                  NULL);
317   }
318
319   /*
320    * Ensure we have sent and processed these release packets
321    * before returning - we don't want to process any election
322    * packets before dealing with the 1d release.
323    */
324
325   retransmit_or_expire_response_records(time(NULL));
326 }
327
328 /****************************************************************************
329   Success in registering the WORKGROUP<1d> name.
330   We are now *really* a local master browser.
331   ****************************************************************************/
332
333 static void become_local_master_stage2(struct subnet_record *subrec,
334                                         struct userdata_struct *userdata,
335                                         struct nmb_name *registered_name,
336                                         uint16 nb_flags,
337                                         int ttl, struct in_addr registered_ip)
338 {
339   int i = 0;
340   struct server_record *sl;
341   struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
342   struct server_record *servrec;
343
344   if(!work)
345   {
346     DEBUG(0,("become_local_master_stage2: Error - cannot find \
347 workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
348     return;
349   }
350
351   if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
352   {
353     DEBUG(0,("become_local_master_stage2: Error - cannot find server %s \
354 in workgroup %s on subnet %s\n",
355        global_myname, registered_name->name, subrec->subnet_name));
356     work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
357     return;
358   }
359   
360   DEBUG(3,("become_local_master_stage2: registered as master browser for workgroup %s \
361 on subnet %s\n", work->work_group, subrec->subnet_name));
362
363   work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
364
365   /* update our server status */
366   servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
367   servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
368
369   /* Tell the namelist writer to write out a change. */
370   subrec->work_changed = True;
371
372   /* Add this name to the workgroup as local master browser. */
373   set_workgroup_local_master_browser_name( work, global_myname);
374
375   /* Count the number of servers we have on our list. If it's
376      less than 10 (just a heuristic) request the servers
377      to announce themselves.
378    */
379   for( sl = work->serverlist; sl != NULL; sl = sl->next)
380     i++;
381
382   if (i < 10)
383   {
384     /* Ask all servers on our local net to announce to us. */
385     broadcast_announce_request(subrec, work);
386   }
387
388   /*
389    * Now we are a local master on a broadcast subnet, we need to add
390    * the WORKGROUP<1d> name to the unicast subnet so that we can answer
391    * unicast requests sent to this name. We can create this name directly on
392    * the unicast subnet as a WINS server always returns true when registering
393    * this name, and discards the registration. We use the number of IP
394    * addresses registered to this name as a reference count, as we
395    * remove this broadcast subnet IP address from it when we stop becoming a local
396    * master browser for this broadcast subnet.
397    */
398
399   insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
400
401   /* Reset the announce master browser timer so that we try and tell a domain
402      master browser as soon as possible that we are a local master browser. */
403   reset_announce_timer();
404
405   if( DEBUGLVL( 0 ) )
406   {
407     dbgtext( "*****\n\n" );
408     dbgtext( "Samba name server %s ", global_myname );
409     dbgtext( "is now a local master browser " );
410     dbgtext( "for workgroup %s ", work->work_group );
411     dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
412   }
413
414 }
415
416 /****************************************************************************
417   Failed to register the WORKGROUP<1d> name.
418   ****************************************************************************/
419 static void become_local_master_fail2(struct subnet_record *subrec,
420                                       struct response_record *rrec,
421                                       struct nmb_name *fail_name)
422 {
423   struct work_record *work = find_workgroup_on_subnet( subrec, fail_name->name);
424
425   DEBUG(0,("become_local_master_fail2: failed to register name %s on subnet %s. \
426 Failed to become a local master browser.\n", nmb_namestr(fail_name), subrec->subnet_name));
427
428   if(!work)
429   {
430     DEBUG(0,("become_local_master_fail2: Error - cannot find \
431 workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
432     return;
433   }
434
435   /* Roll back all the way by calling unbecome_local_master_browser(). */
436   unbecome_local_master_browser(subrec, work, False);
437 }
438
439 /****************************************************************************
440   Success in registering the MSBROWSE name.
441   ****************************************************************************/
442
443 static void become_local_master_stage1(struct subnet_record *subrec,
444                                         struct userdata_struct *userdata,
445                                         struct nmb_name *registered_name,
446                                         uint16 nb_flags,
447                                         int ttl, struct in_addr registered_ip)
448 {
449   char *work_name = userdata->data;
450   struct work_record *work = find_workgroup_on_subnet( subrec, work_name);
451
452   if(!work)
453   {
454     DEBUG(0,("become_local_master_stage1: Error - cannot find \
455 workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
456     return;
457   }
458
459   DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n",
460             work->work_group));
461
462   work->mst_state = MST_MSB; /* Registering MSBROWSE was successful. */
463
464   /*
465    * We registered the MSBROWSE name on a broadcast subnet, now need to add
466    * the MSBROWSE name to the unicast subnet so that we can answer
467    * unicast requests sent to this name. We create this name directly on
468    * the unicast subnet.
469    */
470
471   insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
472
473   /* Attempt to register the WORKGROUP<1d> name. */
474   register_name(subrec, work->work_group,0x1d,samba_nb_type,
475                 become_local_master_stage2,
476                 become_local_master_fail2,
477                 NULL);
478 }
479
480 /****************************************************************************
481   Failed to register the MSBROWSE name.
482   ****************************************************************************/
483
484 static void become_local_master_fail1(struct subnet_record *subrec,
485                                       struct response_record *rrec,
486                                       struct nmb_name *fail_name)
487 {
488   char *work_name = rrec->userdata->data;
489   struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
490
491   if(!work)
492   {
493     DEBUG(0,("become_local_master_fail1: Error - cannot find \
494 workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
495     return;
496   }
497
498   if(find_server_in_workgroup(work, global_myname) == NULL)
499   {
500     DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
501 in workgroup %s on subnet %s\n",
502        global_myname, work->work_group, subrec->subnet_name));
503     return;
504   }
505
506   reset_workgroup_state( subrec, work->work_group, False );
507
508   DEBUG(0,("become_local_master_fail1: Failed to become a local master browser for \
509 workgroup %s on subnet %s. Couldn't register name %s.\n",
510        work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
511 }
512
513 /******************************************************************
514   Become the local master browser on a subnet.
515   This gets called if we win an election on this subnet.
516
517   Stage 1: mst_state was MST_POTENTIAL - go to MST_BACK register ^1^2__MSBROWSE__^2^1.
518   Stage 2: mst_state was MST_BACKUP  - go to MST_MSB  and register WORKGROUP<1d>.
519   Stage 3: mst_state was MST_MSB  - go to MST_BROWSER.
520 ******************************************************************/
521
522 void become_local_master_browser(struct subnet_record *subrec, struct work_record *work)
523 {
524   struct userdata_struct *userdata;
525   int size = sizeof(struct userdata_struct) + sizeof(fstring) + 1;
526
527   /* Sanity check. */
528   if (!lp_local_master())
529   { 
530     DEBUG(0,("become_local_master_browser: Samba not configured as a local master browser.\n"));
531     return;
532   }
533
534   if(!AM_POTENTIAL_MASTER_BROWSER(work))
535   {
536     DEBUG(2,("become_local_master_browser: Awaiting potential browser state. Current state is %d\n",
537               work->mst_state ));
538     return;
539   }
540
541   if(find_server_in_workgroup( work, global_myname) == NULL)
542   {
543     DEBUG(0,("become_local_master_browser: Error - cannot find server %s \
544 in workgroup %s on subnet %s\n",
545        global_myname, work->work_group, subrec->subnet_name));
546     return;
547   }
548
549   DEBUG(2,("become_local_master_browser: Starting to become a master browser for workgroup \
550 %s on subnet %s\n", work->work_group, subrec->subnet_name));
551   
552   DEBUG(3,("become_local_master_browser: first stage - attempt to register ^1^2__MSBROWSE__^2^1\n"));
553   work->mst_state = MST_BACKUP; /* an election win was successful */
554
555   work->ElectionCriterion |= 0x5;
556
557   /* Tell the namelist writer to write out a change. */
558   subrec->work_changed = True;
559
560   /* Setup the userdata_struct. */
561   if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
562   {
563     DEBUG(0,("become_local_master_browser: malloc fail.\n"));
564     return;
565   }
566
567   userdata->copy_fn = NULL;
568   userdata->free_fn = NULL;
569   userdata->userdata_len = strlen(work->work_group)+1;
570   pstrcpy(userdata->data, work->work_group);
571
572   /* Register the special browser group name. */
573   register_name(subrec, MSBROWSE, 0x01, samba_nb_type|NB_GROUP,
574                 become_local_master_stage1,
575                 become_local_master_fail1,
576                 userdata);
577
578   zero_free(userdata, size);
579 }
580
581 /***************************************************************
582  Utility function to set the local master browser name. Does
583  some sanity checking as old versions of Samba seem to sometimes
584  say that the master browser name for a workgroup is the same
585  as the workgroup name.
586 ****************************************************************/
587
588 void set_workgroup_local_master_browser_name( struct work_record *work, char *newname)
589 {
590   DEBUG(5,("set_workgroup_local_master_browser_name: setting local master name to '%s' \
591 for workgroup %s.\n", newname, work->work_group ));
592
593 #if 0
594   /*
595    * Apparently some sites use the workgroup name as the local
596    * master browser name. Arrrrggghhhhh ! (JRA).
597    */
598   if(strequal( work->work_group, newname))
599   {
600     DEBUG(5, ("set_workgroup_local_master_browser_name: Refusing to set \
601 local_master_browser_name for workgroup %s to workgroup name.\n",
602          work->work_group ));
603     return;
604   }
605 #endif
606
607   StrnCpy(work->local_master_browser_name, newname,
608             sizeof(work->local_master_browser_name)-1);
609 }