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-1998
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.
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.
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.
27 extern pstring global_myname;
28 extern fstring global_myworkgroup;
30 /* This is our local master browser list database. */
31 extern ubi_dlList lmb_browserlist[];
33 /****************************************************************************
34 As a domain master browser, do a sync with a local master browser.
35 **************************************************************************/
36 static void sync_with_lmb(struct browse_cache_record *browc)
38 struct work_record *work;
40 if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) )
44 dbgtext( "sync_with_lmb:\n" );
45 dbgtext( "Failed to get a workgroup for a local master browser " );
46 dbgtext( "cache entry workgroup " );
47 dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
52 /* We should only be doing this if we are a domain master browser for
53 the given workgroup. Ensure this is so. */
55 if(!AM_DOMAIN_MASTER_BROWSER(work))
59 dbgtext( "sync_with_lmb:\n" );
60 dbgtext( "We are trying to sync with a local master browser " );
61 dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
62 dbgtext( "and we are not a domain master browser on this workgroup.\n" );
63 dbgtext( "Error!\n" );
70 dbgtext( "sync_with_lmb:\n" );
71 dbgtext( "Initiating sync with local master browser " );
72 dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
73 dbgtext( "for workgroup %s\n", browc->work_group );
76 sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
78 browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
81 /****************************************************************************
82 Sync or expire any local master browsers.
83 **************************************************************************/
84 void dmb_expire_and_sync_browser_lists(time_t t)
86 static time_t last_run = 0;
87 struct browse_cache_record *browc;
89 /* Only do this every 20 seconds. */
90 if (t - last_run < 20)
95 expire_lmb_browsers(t);
97 for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
99 browc = (struct browse_cache_record *)ubi_dlNext( browc ) )
101 if (browc->sync_time < t)
102 sync_with_lmb(browc);
106 /****************************************************************************
107 As a local master browser, send an announce packet to the domain master browser.
108 **************************************************************************/
110 static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
115 if(ismyip(work->dmb_addr))
119 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
120 dbgtext( "We are both a domain and a local master browser for " );
121 dbgtext( "workgroup %s. ", work->work_group );
122 dbgtext( "Do not announce to ourselves.\n" );
127 memset(outbuf,'\0',sizeof(outbuf));
129 SCVAL(p,0,ANN_MasterAnnouncement);
132 StrnCpy(p,global_myname,15);
134 p = skip_string(p,1);
138 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
139 dbgtext( "Sending local master announce to " );
140 dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
144 send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
145 global_myname, 0x0, work->dmb_name.name, 0x0,
146 work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
150 /****************************************************************************
151 As a local master browser, do a sync with a domain master browser.
152 **************************************************************************/
154 static void sync_with_dmb(struct work_record *work)
158 dbgtext( "sync_with_dmb:\n" );
159 dbgtext( "Initiating sync with domain master browser " );
160 dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
161 dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
162 dbgtext( "for workgroup %s\n", work->work_group );
165 sync_browse_lists(work, work->dmb_name.name, work->dmb_name.name_type,
166 work->dmb_addr, False, True);
169 /****************************************************************************
170 Function called when a node status query to a domain master browser IP succeeds.
171 ****************************************************************************/
173 static void domain_master_node_status_success(struct subnet_record *subrec,
174 struct userdata_struct *userdata,
175 struct res_rec *answers,
176 struct in_addr from_ip)
178 struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
184 dbgtext( "domain_master_node_status_success:\n" );
185 dbgtext( "Unable to find workgroup " );
186 dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
193 dbgtext( "domain_master_node_status_success:\n" );
194 dbgtext( "Success in node status for workgroup " );
195 dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
198 /* Go through the list of names found at answers->rdata and look for
199 the first SERVER<0x20> name. */
201 if(answers->rdata != NULL)
203 char *p = answers->rdata;
204 int numnames = CVAL(p, 0);
215 name_type = CVAL(p,15);
216 nb_flags = get_nb_flags(&p[16]);
217 trim_string(qname,NULL," ");
221 if(!(nb_flags & NB_GROUP) && (name_type == 0x20))
223 struct nmb_name nmbname;
225 make_nmb_name(&nmbname, qname, name_type);
227 /* Copy the dmb name and IP address
228 into the workgroup struct. */
230 work->dmb_name = nmbname;
231 putip((char *)&work->dmb_addr, &from_ip);
233 /* Do the local master browser announcement to the domain
234 master browser name and IP. */
235 announce_local_master_browser_to_domain_master_browser( work );
237 /* Now synchronise lists with the domain master browser. */
246 dbgtext( "domain_master_node_status_success:\n" );
247 dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
248 dbgtext( "%s.\n", inet_ntoa(from_ip) );
252 /****************************************************************************
253 Function called when a node status query to a domain master browser IP fails.
254 ****************************************************************************/
256 static void domain_master_node_status_fail(struct subnet_record *subrec,
257 struct response_record *rrec)
259 struct userdata_struct *userdata = rrec->userdata;
263 dbgtext( "domain_master_node_status_fail:\n" );
264 dbgtext( "Doing a node status request to the domain master browser\n" );
265 dbgtext( "for workgroup %s ", userdata->data );
266 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
267 dbgtext( "Cannot sync browser lists.\n" );
271 /****************************************************************************
272 Function called when a query for a WORKGROUP<1b> name succeeds.
273 ****************************************************************************/
275 static void find_domain_master_name_query_success(struct subnet_record *subrec,
276 struct userdata_struct *userdata_in,
277 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
280 * Unfortunately, finding the IP address of the Domain Master Browser,
281 * as we have here, is not enough. We need to now do a sync to the
282 * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
283 * respond to the SMBSERVER name. To get this name from IP
284 * address we do a Node status request, and look for the first
285 * NAME<0x20> in the response, and take that as the server name.
286 * We also keep a cache of the Domain Master Browser name for this
287 * workgroup in the Workgroup struct, so that if the same IP addess
288 * is returned every time, we don't need to do the node status
292 struct work_record *work;
293 struct nmb_name nmbname;
294 struct userdata_struct *userdata;
295 int size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
297 if( !(work = find_workgroup_on_subnet(subrec, q_name->name)) )
301 dbgtext( "find_domain_master_name_query_success:\n" );
302 dbgtext( "Failed to find workgroup %s\n", q_name->name );
307 /* First check if we already have a dmb for this workgroup. */
309 if(!is_zero_ip(work->dmb_addr) && ip_equal(work->dmb_addr, answer_ip))
311 /* Do the local master browser announcement to the domain
312 master browser name and IP. */
313 announce_local_master_browser_to_domain_master_browser( work );
315 /* Now synchronise lists with the domain master browser. */
320 zero_ip(&work->dmb_addr);
322 /* Now initiate the node status request. */
323 make_nmb_name(&nmbname,"*",0x0);
325 /* Put the workgroup name into the userdata so we know
326 what workgroup we're talking to when the reply comes
329 /* Setup the userdata_struct - this is copied so we can use
330 a stack variable for this. */
331 if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
333 DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
337 userdata->copy_fn = NULL;
338 userdata->free_fn = NULL;
339 userdata->userdata_len = strlen(work->work_group)+1;
340 pstrcpy(userdata->data, work->work_group);
342 node_status( subrec, &nmbname, answer_ip,
343 domain_master_node_status_success,
344 domain_master_node_status_fail,
347 zero_free(userdata, size);
350 /****************************************************************************
351 Function called when a query for a WORKGROUP<1b> name fails.
352 ****************************************************************************/
353 static void find_domain_master_name_query_fail(struct subnet_record *subrec,
354 struct response_record *rrec,
355 struct nmb_name *question_name, int fail_code)
359 dbgtext( "find_domain_master_name_query_fail:\n" );
360 dbgtext( "Unable to find the Domain Master Browser name " );
361 dbgtext( "%s for the workgroup %s.\n",
362 nmb_namestr(question_name), question_name->name );
363 dbgtext( "Unable to sync browse lists in this workgroup.\n" );
367 /****************************************************************************
368 As a local master browser for a workgroup find the domain master browser
369 name, announce ourselves as local master browser to it and then pull the
370 full domain browse lists from it onto the given subnet.
371 **************************************************************************/
373 void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
374 struct work_record *work)
376 struct nmb_name nmbname;
378 /* Only do this if we are using a WINS server. */
379 if(we_are_a_wins_client() == False)
383 dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
384 dbgtext( "Ignoring, as we are not a WINS client.\n" );
389 make_nmb_name(&nmbname,work->work_group,0x1b);
391 /* First, query for the WORKGROUP<1b> name from the WINS server. */
392 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
393 find_domain_master_name_query_success,
394 find_domain_master_name_query_fail,
399 /****************************************************************************
400 Function called when a node status query to a domain master browser IP succeeds.
401 This function is only called on query to a Samba 1.9.18 or above WINS server.
403 Note that adding the workgroup name is enough for this workgroup to be
404 browsable by clients, as clients query the WINS server or broadcast
405 nets for the WORKGROUP<1b> name when they want to browse a workgroup
406 they are not in. We do not need to do a sync with this Domain Master
407 Browser in order for our browse clients to see machines in this workgroup.
409 ****************************************************************************/
411 static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
412 struct userdata_struct *userdata,
413 struct res_rec *answers,
414 struct in_addr from_ip)
416 struct work_record *work;
423 dbgtext( "get_domain_master_name_node_status_success:\n" );
424 dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
428 * Go through the list of names found at answers->rdata and look for
429 * the first WORKGROUP<0x1b> name.
432 if(answers->rdata != NULL)
434 char *p = answers->rdata;
435 int numnames = CVAL(p, 0);
446 name_type = CVAL(p,15);
447 nb_flags = get_nb_flags(&p[16]);
448 trim_string(qname,NULL," ");
452 if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
453 server_name[0] == 0) {
454 /* this is almost certainly the server netbios name */
455 fstrcpy(server_name, qname);
459 if(!(nb_flags & NB_GROUP) && (name_type == 0x1b))
463 dbgtext( "get_domain_master_name_node_status_success:\n" );
464 dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
465 dbgtext( "is a domain master browser for workgroup " );
466 dbgtext( "%s. Adding this name.\n", qname );
470 * If we don't already know about this workgroup, add it
471 * to the workgroup list on the unicast_subnet.
473 if((work = find_workgroup_on_subnet( subrec, qname)) == NULL)
475 struct nmb_name nmbname;
477 * Add it - with an hour in the cache.
479 if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
482 /* remember who the master is */
483 fstrcpy(work->local_master_browser_name, server_name);
484 make_nmb_name(&nmbname, server_name, 0x20);
485 work->dmb_name = nmbname;
486 work->dmb_addr = from_ip;
495 dbgtext( "get_domain_master_name_node_status_success:\n" );
496 dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
497 dbgtext( "%s.\n", inet_ntoa(from_ip) );
501 /****************************************************************************
502 Function called when a node status query to a domain master browser IP fails.
503 ****************************************************************************/
505 static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
506 struct response_record *rrec)
510 dbgtext( "get_domain_master_name_node_status_fail:\n" );
511 dbgtext( "Doing a node status request to the domain master browser " );
512 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
513 dbgtext( "Cannot get workgroup name.\n" );
517 /****************************************************************************
518 Function called when a query for *<1b> name succeeds.
519 ****************************************************************************/
521 static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
522 struct userdata_struct *userdata_in,
523 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
526 * We now have a list of all the domain master browsers for all workgroups
527 * that have registered with the WINS server. Now do a node status request
528 * to each one and look for the first 1b name in the reply. This will be
529 * the workgroup name that we will add to the unicast subnet as a 'non-local'
533 struct nmb_name nmbname;
534 struct in_addr send_ip;
539 dbgtext( "find_all_domain_master_names_query_succes:\n" );
540 dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
541 dbgtext( "IP addresses for Domain Master Browsers.\n" );
544 for(i = 0; i < rrec->rdlength / 6; i++)
546 /* Initiate the node status requests. */
547 make_nmb_name(&nmbname, "*", 0);
549 putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
552 * Don't send node status requests to ourself.
555 if(ismyip( send_ip ))
559 dbgtext( "find_all_domain_master_names_query_succes:\n" );
560 dbgtext( "Not sending node status to our own IP " );
561 dbgtext( "%s.\n", inet_ntoa(send_ip) );
568 dbgtext( "find_all_domain_master_names_query_success:\n" );
569 dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
572 node_status( subrec, &nmbname, send_ip,
573 get_domain_master_name_node_status_success,
574 get_domain_master_name_node_status_fail,
579 /****************************************************************************
580 Function called when a query for *<1b> name fails.
581 ****************************************************************************/
582 static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
583 struct response_record *rrec,
584 struct nmb_name *question_name, int fail_code)
588 dbgtext( "find_domain_master_name_query_fail:\n" );
589 dbgtext( "WINS server did not reply to a query for name " );
590 dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
591 dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
595 /****************************************************************************
596 If we are a domain master browser on the unicast subnet, do a query to the
597 WINS server for the *<1b> name. This will only work to a Samba WINS server,
598 so ignore it if we fail. If we succeed, contact each of the IP addresses in
599 turn and do a node status request to them. If this succeeds then look for a
600 <1b> name in the reply - this is the workgroup name. Add this to the unicast
601 subnet. This is expensive, so we only do this every 15 minutes.
602 **************************************************************************/
603 void collect_all_workgroup_names_from_wins_server(time_t t)
605 static time_t lastrun = 0;
606 struct work_record *work;
607 struct nmb_name nmbname;
609 /* Only do this if we are using a WINS server. */
610 if(we_are_a_wins_client() == False)
613 /* Check to see if we are a domain master browser on the unicast subnet. */
614 if((work = find_workgroup_on_subnet( unicast_subnet, global_myworkgroup)) == NULL)
618 dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
619 dbgtext( "Cannot find my workgroup %s ", global_myworkgroup );
620 dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
625 if(!AM_DOMAIN_MASTER_BROWSER(work))
628 if ((lastrun != 0) && (t < lastrun + (15 * 60)))
633 make_nmb_name(&nmbname,"*",0x1b);
635 /* First, query for the *<1b> name from the WINS server. */
636 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
637 find_all_domain_master_names_query_success,
638 find_all_domain_master_names_query_fail,
643 /****************************************************************************
644 If we are a domain master browser on the unicast subnet, do a regular sync
645 with all other DMBs that we know of on that subnet.
647 To prevent exponential network traffic with large numbers of workgroups
648 we use a randomised system where sync probability is inversely proportional
649 to the number of known workgroups
650 **************************************************************************/
651 void sync_all_dmbs(time_t t)
653 static time_t lastrun = 0;
654 struct work_record *work;
657 /* Only do this if we are using a WINS server. */
658 if(we_are_a_wins_client() == False)
661 /* Check to see if we are a domain master browser on the
663 work = find_workgroup_on_subnet(unicast_subnet, global_myworkgroup);
666 if (!AM_DOMAIN_MASTER_BROWSER(work))
669 if ((lastrun != 0) && (t < lastrun + (5 * 60)))
672 /* count how many syncs we might need to do */
673 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
674 if (strcmp(global_myworkgroup, work->work_group)) {
679 /* sync with a probability of 1/count */
680 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
681 if (strcmp(global_myworkgroup, work->work_group)) {
682 if (((unsigned)sys_random()) % count != 0) continue;
686 if (!work->dmb_name.name[0]) {
687 /* we don't know the DMB - assume it is
688 the same as the unicast local master */
689 make_nmb_name(&work->dmb_name,
690 work->local_master_browser_name,
694 DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
696 inet_ntoa(work->dmb_addr)));
697 sync_browse_lists(work,
699 work->dmb_name.name_type,
700 work->dmb_addr, False, False);