This looks like a big change but really isn't.
[ira/wip.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 scope;
29 extern pstring global_myname;
30
31 extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
32
33 /*******************************************************************
34  Utility function to add a name to the unicast subnet, or add in
35  our IP address if it already exists.
36 ******************************************************************/
37
38 void insert_permanent_name_into_unicast( struct subnet_record *subrec, 
39                                                 struct nmb_name *nmbname, uint16 nb_type )
40 {
41   struct name_record *namerec;
42
43   if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL)
44   {
45     /* The name needs to be created on the unicast subnet. */
46     add_name_to_subnet( unicast_subnet, nmbname->name, nmbname->name_type,
47                         nb_type, 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->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 {
82   struct work_record *work;
83   struct server_record *servrec;
84   struct nmb_name nmbname;
85
86   if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL)
87   {
88     DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
89 subnet %s.\n", workgroup_name, subrec->subnet_name ));
90     return;
91   }
92
93   if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
94   {
95     DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
96 in workgroup %s on subnet %s\n",
97        global_myname, work->work_group, subrec->subnet_name));
98     work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
99     return;
100   }
101
102   /* Update our server status - remove any master flag and replace
103    it with the potential browser flag. */
104   servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
105   servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
106
107   /* Tell the namelist writer to write out a change. */
108   subrec->work_changed = True;
109
110   /* Reset our election flags. */
111   work->ElectionCriterion &= ~0x4;
112
113   work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
114
115   /* Forget who the local master browser was for
116      this workgroup. */
117
118   set_workgroup_local_master_browser_name( work, "");
119
120   /*
121    * Ensure the IP address of this subnet is not registered as one
122    * of the IP addresses of the WORKGROUP<1d> name on the unicast
123    * subnet. This undoes what we did below when we became a local
124    * master browser.
125    */
126
127   make_nmb_name(&nmbname, work->work_group, 0x1d, scope);
128
129   remove_permanent_name_from_unicast( subrec, &nmbname);
130
131 }
132
133 /*******************************************************************
134   Unbecome the local master browser name release success function.
135 ******************************************************************/
136
137 void unbecome_local_master_success(struct subnet_record *subrec,
138                              struct userdata_struct *userdata,
139                              struct nmb_name *released_name,
140                              struct in_addr released_ip)
141
142   DEBUG(3,("unbecome_local_master_success: released name %s.\n",
143              namestr(released_name)));
144
145   /* Now reset the workgroup and server state. */
146   reset_workgroup_state( subrec, released_name->name );
147
148   DEBUG(0,("\n%s *****   Samba name server %s has stopped being a local master browser for workgroup %s \
149 on subnet %s *****\n\n", timestring(), global_myname, released_name->name, subrec->subnet_name));
150
151 }
152
153 /*******************************************************************
154   Unbecome the local master browser name release fail function.
155 ******************************************************************/
156
157 void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec,
158                        struct nmb_name *fail_name)
159 {
160   struct name_record *namerec;
161
162   DEBUG(0,("unbecome_local_master_fail: failed to release name %s. \
163 Removing from namelist anyway.\n", namestr(fail_name)));
164
165   /* Do it anyway. */
166   namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
167   if(namerec)
168     remove_name_from_namelist(subrec, namerec);
169
170   /* Now reset the workgroup and server state. */
171   reset_workgroup_state( subrec, fail_name->name );
172
173   DEBUG(0,("\n%s *****   Samba name server %s has stopped being a local master browser for workgroup %s \
174 on subnet %s *****\n\n", timestring(), global_myname, fail_name->name, subrec->subnet_name));
175
176 }
177
178 /*******************************************************************
179  Utility function to remove the WORKGROUP<1d> name called by both
180  success and fail of releasing the MSBROWSE name.
181 ******************************************************************/
182
183 void release_1d_name( struct subnet_record *subrec, char *workgroup_name)
184 {
185   struct nmb_name nmbname;
186   struct name_record *namerec;
187
188   make_nmb_name(&nmbname, workgroup_name, 0x1d, scope);
189   if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
190   {
191     release_name(subrec, namerec,
192                  unbecome_local_master_success,
193                  unbecome_local_master_fail,
194                  NULL);
195   }
196 }
197
198 /*******************************************************************
199  Unbecome the local master browser MSBROWSE name release success function.
200 ******************************************************************/
201
202 static void release_msbrowse_name_success(struct subnet_record *subrec,
203                       struct userdata_struct *userdata,
204                       struct nmb_name *released_name,
205                       struct in_addr released_ip)
206 {
207   DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
208            namestr(released_name), subrec->subnet_name ));
209
210   /* Remove the permanent MSBROWSE name added into the unicast subnet. */
211   remove_permanent_name_from_unicast( subrec, released_name);
212
213   release_1d_name( subrec, userdata->data );
214 }
215
216 /*******************************************************************
217  Unbecome the local master browser MSBROWSE name release fail function.
218 ******************************************************************/
219
220 static void release_msbrowse_name_fail( struct subnet_record *subrec, 
221                        struct response_record *rrec,
222                        struct nmb_name *fail_name)
223 {
224   struct userdata_struct *userdata = rrec->userdata;
225   struct name_record *namerec;
226
227   DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
228            namestr(fail_name), subrec->subnet_name ));
229
230   /* Release the name anyway. */
231   namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
232   if(namerec)
233     remove_name_from_namelist(subrec, namerec);
234
235   /* Remove the permanent MSBROWSE name added into the unicast subnet. */
236   remove_permanent_name_from_unicast( subrec, fail_name);
237
238   release_1d_name( subrec, userdata->data );
239 }
240
241 /*******************************************************************
242   Unbecome the local master browser.
243 ******************************************************************/
244
245 void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work)
246 {
247   struct server_record *servrec;
248   struct name_record *namerec;
249   struct nmb_name nmbname;
250   struct userdata_struct *userdata;
251
252   /* Sanity check. */
253
254   DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \
255 on subnet %s\n",work->work_group, subrec->subnet_name));
256   
257   if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
258   {
259     DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
260 in workgroup %s on subnet %s\n",
261        global_myname, work->work_group, subrec->subnet_name));
262     work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
263     return;
264   }
265   
266   /* Set the state to unbecoming. */
267   work->mst_state = MST_UNBECOMING_MASTER;
268
269   /* Setup the userdata for the MSBROWSE name release. */
270   if((userdata = (struct userdata_struct *)malloc( sizeof(struct userdata_struct) + sizeof(fstring)+1)) == NULL)
271   {
272     DEBUG(0,("unbecome_local_master_browser: malloc fail.\n"));
273     return;
274   }
275
276   userdata->copy_fn = NULL;
277   userdata->free_fn = NULL;
278   userdata->userdata_len = strlen(work->work_group)+1;
279   strcpy(userdata->data, work->work_group);
280
281   /* Deregister any browser names we may have. */
282   make_nmb_name(&nmbname, MSBROWSE, 0x1, scope);
283   if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL)
284   {
285     release_name(subrec, namerec,
286                  release_msbrowse_name_success,
287                  release_msbrowse_name_fail,
288                  userdata);
289   }
290
291   free((char *)userdata);
292 }
293
294 /****************************************************************************
295   Success in registering the WORKGROUP<1d> name.
296   We are now *really* a local master browser.
297   ****************************************************************************/
298
299 static void become_local_master_stage2(struct subnet_record *subrec,
300                                         struct userdata_struct *userdata,
301                                         struct nmb_name *registered_name,
302                                         uint16 nb_flags,
303                                         int ttl, struct in_addr registered_ip)
304 {
305   int i = 0;
306   struct server_record *sl;
307   struct work_record *work = find_workgroup_on_subnet( subrec, registered_name->name);
308   struct server_record *servrec;
309
310   if(!work)
311   {
312     DEBUG(0,("become_local_master_stage2: Error - cannot find \
313 workgroup %s on subnet %s\n", registered_name->name, subrec->subnet_name));
314     return;
315   }
316
317   if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
318   {
319     DEBUG(0,("become_local_master_stage2: Error - cannot find server %s \
320 in workgroup %s on subnet %s\n",
321        global_myname, registered_name->name, subrec->subnet_name));
322     work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
323     return;
324   }
325   
326   DEBUG(3,("become_local_master_stage2: registered as master browser for workgroup %s \
327 on subnet %s\n", work->work_group, subrec->subnet_name));
328
329   work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
330
331   /* update our server status */
332   servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
333   servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
334
335   /* Tell the namelist writer to write out a change. */
336   subrec->work_changed = True;
337
338   /* Add this name to the workgroup as local master browser. */
339   set_workgroup_local_master_browser_name( work, global_myname);
340
341   /* Count the number of servers we have on our list. If it's
342      less than 10 (just a heuristic) request the servers
343      to announce themselves.
344    */
345   for( sl = work->serverlist; sl != NULL; sl = sl->next)
346     i++;
347
348   if (i < 10)
349   {
350     /* Ask all servers on our local net to announce to us. */
351     broadcast_announce_request(subrec, work);
352   }
353
354   /*
355    * Now we are a local master on a broadcast subnet, we need to add
356    * the WORKGROUP<1d> name to the unicast subnet so that we can answer
357    * unicast requests sent to this name. We can create this name directly on
358    * the unicast subnet as a WINS server always returns true when registering
359    * this name, and discards the registration. We use the number of IP
360    * addresses registered to this name as a reference count, as we
361    * remove this broadcast subnet IP address from it when we stop becoming a local
362    * master browser for this broadcast subnet.
363    */
364
365   insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
366
367   /* Reset the announce master browser timer so that we try and tell a domain
368      master browser as soon as possible that we are a local master browser. */
369   reset_announce_timer();
370
371   DEBUG(0,("\n%s *****   Samba name server %s is now a local master browser for workgroup %s \
372 on subnet %s *****\n\n", timestring(), global_myname, work->work_group, subrec->subnet_name));
373
374 }
375
376 /****************************************************************************
377   Failed to register the WORKGROUP<1d> name.
378   ****************************************************************************/
379 static void become_local_master_fail2(struct subnet_record *subrec,
380                                       struct response_record *rrec,
381                                       struct nmb_name *fail_name)
382 {
383   struct work_record *work = find_workgroup_on_subnet( subrec, fail_name->name);
384
385   DEBUG(0,("become_local_master_fail2: failed to register name %s on subnet %s. \
386 Failed to become a local master browser.\n", namestr(fail_name), subrec->subnet_name));
387
388   if(!work)
389   {
390     DEBUG(0,("become_local_master_fail2: Error - cannot find \
391 workgroup %s on subnet %s\n", fail_name->name, subrec->subnet_name));
392     return;
393   }
394
395   /* Roll back all the way by calling unbecome_local_master_browser(). */
396   unbecome_local_master_browser(subrec, work);
397 }
398
399 /****************************************************************************
400   Success in registering the MSBROWSE name.
401   ****************************************************************************/
402
403 static void become_local_master_stage1(struct subnet_record *subrec,
404                                         struct userdata_struct *userdata,
405                                         struct nmb_name *registered_name,
406                                         uint16 nb_flags,
407                                         int ttl, struct in_addr registered_ip)
408 {
409   char *work_name = userdata->data;
410   struct work_record *work = find_workgroup_on_subnet( subrec, work_name);
411
412   if(!work)
413   {
414     DEBUG(0,("become_local_master_stage1: Error - cannot find \
415 workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
416     return;
417   }
418
419   DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n",
420             work->work_group));
421
422   work->mst_state = MST_MSB; /* Registering MSBROWSE was successful. */
423
424   /*
425    * We registered the MSBROWSE name on a broadcast subnet, now need to add
426    * the MSBROWSE name to the unicast subnet so that we can answer
427    * unicast requests sent to this name. We create this name directly on
428    * the unicast subnet.
429    */
430
431   insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
432
433   /* Attempt to register the WORKGROUP<1d> name. */
434   register_name(subrec, work->work_group,0x1d,samba_nb_type,
435                 become_local_master_stage2,
436                 become_local_master_fail2,
437                 NULL);
438 }
439
440 /****************************************************************************
441   Failed to register the MSBROWSE name.
442   ****************************************************************************/
443
444 static void become_local_master_fail1(struct subnet_record *subrec,
445                                       struct response_record *rrec,
446                                       struct nmb_name *fail_name)
447 {
448   char *work_name = rrec->userdata->data;
449   struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
450   struct server_record *servrec;
451
452   if(!work)
453   {
454     DEBUG(0,("become_local_master_fail1: Error - cannot find \
455 workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
456     return;
457   }
458
459   if((servrec = find_server_in_workgroup(work, global_myname)) == NULL)
460   {
461     DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
462 in workgroup %s on subnet %s\n",
463        global_myname, work->work_group, subrec->subnet_name));
464     return;
465   }
466
467   reset_workgroup_state( subrec, work->work_group );
468
469   DEBUG(0,("become_local_master_fail1: Failed to become a local master browser for \
470 workgroup %s on subnet %s. Couldn't register name %s.\n",
471        work->work_group, subrec->subnet_name, namestr(fail_name)));
472 }
473
474 /******************************************************************
475   Become the local master browser on a subnet.
476   This gets called if we win an election on this subnet.
477
478   Stage 1: mst_state was MST_POTENTIAL - go to MST_BACK register ^1^2__MSBROWSE__^2^1.
479   Stage 2: mst_state was MST_BACKUP  - go to MST_MSB  and register WORKGROUP<1d>.
480   Stage 3: mst_state was MST_MSB  - go to MST_BROWSER.
481 ******************************************************************/
482
483 void become_local_master_browser(struct subnet_record *subrec, struct work_record *work)
484 {
485   struct server_record *servrec;
486   struct userdata_struct *userdata;
487
488   /* Sanity check. */
489   if (!lp_local_master())
490   { 
491     DEBUG(0,("become_local_master_browser: Samba not configured as a local master browser.\n"));
492     return;
493   }
494
495   if(!AM_POTENTIAL_MASTER_BROWSER(work))
496   {
497     DEBUG(2,("become_local_master_browser: Awaiting potential browser state. Current state is %d\n",
498               work->mst_state ));
499     return;
500   }
501
502   if((servrec = find_server_in_workgroup( work, global_myname)) == NULL)
503   {
504     DEBUG(0,("become_local_master_browser: Error - cannot find server %s \
505 in workgroup %s on subnet %s\n",
506        global_myname, work->work_group, subrec->subnet_name));
507     return;
508   }
509
510   DEBUG(2,("become_local_master_browser: Starting to become a master browser for workgroup \
511 %s on subnet %s\n", work->work_group, subrec->subnet_name));
512   
513   DEBUG(3,("become_local_master_browser: first stage - attempt to register ^1^2__MSBROWSE__^2^1\n"));
514   work->mst_state = MST_BACKUP; /* an election win was successful */
515
516   work->ElectionCriterion |= 0x5;
517
518   /* Tell the namelist writer to write out a change. */
519   subrec->work_changed = True;
520
521   /* Setup the userdata_struct. */
522   if((userdata = (struct userdata_struct *)malloc(sizeof(struct userdata_struct) + sizeof(fstring)+1)) == NULL)
523   {
524     DEBUG(0,("become_local_master_browser: malloc fail.\n"));
525     return;
526   }
527
528   userdata->copy_fn = NULL;
529   userdata->free_fn = NULL;
530   userdata->userdata_len = strlen(work->work_group)+1;
531   strcpy(userdata->data, work->work_group);
532
533   /* Register the special browser group name. */
534   register_name(subrec, MSBROWSE, 0x01, samba_nb_type|NB_GROUP,
535                 become_local_master_stage1,
536                 become_local_master_fail1,
537                 userdata);
538
539   free((char *)userdata);
540 }
541
542 /***************************************************************
543  Utility function to set the local master browser name. Does
544  some sanity checking as old versions of Samba seem to sometimes
545  say that the master browser name for a workgroup is the same
546  as the workgroup name.
547 ****************************************************************/
548
549 void set_workgroup_local_master_browser_name( struct work_record *work, char *newname)
550 {
551   DEBUG(5,("set_workgroup_local_master_browser_name: setting local master name to '%s' \
552 for workgroup %s.\n", newname, work->work_group ));
553
554 #if 0
555   /*
556    * Apparently some sites use the workgroup name as the local
557    * master browser name. Arrrrggghhhhh ! (JRA).
558    */
559   if(strequal( work->work_group, newname))
560   {
561     DEBUG(5, ("set_workgroup_local_master_browser_name: Refusing to set \
562 local_master_browser_name for workgroup %s to workgroup name.\n",
563          work->work_group ));
564     return;
565   }
566 #endif
567
568   StrnCpy(work->local_master_browser_name, newname,
569             sizeof(work->local_master_browser_name)-1);
570 }