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