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