source: branches/samba-3.0/source/nmbd/nmbd_become_lmb.c@ 612

Last change on this file since 612 was 1, checked in by Paul Smedley, 19 years ago

Initial code import

File size: 21.2 KB
Line 
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
26extern 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
33void insert_permanent_name_into_unicast( struct subnet_record *subrec,
34 struct nmb_name *nmbname, uint16 nb_type )
35{
36 unstring 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
56static 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
74static 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 \
83subnet %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 \
89in 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
132static 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 unstring 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
163static 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 unstring 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. \
174Removing 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
198static 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 *)SMB_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
232static 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
248static 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
271void 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 \
280on 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 \
284in 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
323static 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 unstring 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 \
340workgroup %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 \
346in 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 \
353on 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
409static void become_local_master_fail2(struct subnet_record *subrec,
410 struct response_record *rrec,
411 struct nmb_name *fail_name)
412{
413 unstring failname;
414 struct work_record *work;
415
416 DEBUG(0,("become_local_master_fail2: failed to register name %s on subnet %s. \
417Failed 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 \
424workgroup %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
436static 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
476static 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 \
485workgroup %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 \
491in 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 \
499workgroup %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
512void 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 \
531in 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 *)SMB_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
574void 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' \
577for 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 \
587local_master_browser_name for workgroup %s to workgroup name.\n",
588 work->work_group ));
589 return;
590 }
591#endif
592
593 unstrcpy(work->local_master_browser_name, newname);
594}
Note: See TracBrowser for help on using the repository browser.