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