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