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.
26 /* This is our local master browser list database. */
27 extern ubi_dlList lmb_browserlist[];
29 /****************************************************************************
30 As a domain master browser, do a sync with a local master browser.
31 **************************************************************************/
32 static void sync_with_lmb(struct browse_cache_record *browc)
34 struct work_record *work;
36 if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) )
40 dbgtext( "sync_with_lmb:\n" );
41 dbgtext( "Failed to get a workgroup for a local master browser " );
42 dbgtext( "cache entry workgroup " );
43 dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
48 /* We should only be doing this if we are a domain master browser for
49 the given workgroup. Ensure this is so. */
51 if(!AM_DOMAIN_MASTER_BROWSER(work))
55 dbgtext( "sync_with_lmb:\n" );
56 dbgtext( "We are trying to sync with a local master browser " );
57 dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
58 dbgtext( "and we are not a domain master browser on this workgroup.\n" );
59 dbgtext( "Error!\n" );
66 dbgtext( "sync_with_lmb:\n" );
67 dbgtext( "Initiating sync with local master browser " );
68 dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
69 dbgtext( "for workgroup %s\n", browc->work_group );
72 sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
74 browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
77 /****************************************************************************
78 Sync or expire any local master browsers.
79 **************************************************************************/
80 void dmb_expire_and_sync_browser_lists(time_t t)
82 static time_t last_run = 0;
83 struct browse_cache_record *browc;
85 /* Only do this every 20 seconds. */
86 if (t - last_run < 20)
91 expire_lmb_browsers(t);
93 for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
95 browc = (struct browse_cache_record *)ubi_dlNext( browc ) )
97 if (browc->sync_time < t)
102 /****************************************************************************
103 As a local master browser, send an announce packet to the domain master browser.
104 **************************************************************************/
106 static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
111 if(ismyip(work->dmb_addr))
115 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
116 dbgtext( "We are both a domain and a local master browser for " );
117 dbgtext( "workgroup %s. ", work->work_group );
118 dbgtext( "Do not announce to ourselves.\n" );
123 memset(outbuf,'\0',sizeof(outbuf));
125 SCVAL(p,0,ANN_MasterAnnouncement);
128 StrnCpy(p,global_myname(),15);
130 p = skip_string(p,1);
134 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
135 dbgtext( "Sending local master announce to " );
136 dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
140 send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
141 global_myname(), 0x0, work->dmb_name.name, 0x0,
142 work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
146 /****************************************************************************
147 As a local master browser, do a sync with a domain master browser.
148 **************************************************************************/
150 static void sync_with_dmb(struct work_record *work)
154 dbgtext( "sync_with_dmb:\n" );
155 dbgtext( "Initiating sync with domain master browser " );
156 dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
157 dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
158 dbgtext( "for workgroup %s\n", work->work_group );
161 sync_browse_lists(work, work->dmb_name.name, work->dmb_name.name_type,
162 work->dmb_addr, False, True);
165 /****************************************************************************
166 Function called when a node status query to a domain master browser IP succeeds.
167 ****************************************************************************/
169 static void domain_master_node_status_success(struct subnet_record *subrec,
170 struct userdata_struct *userdata,
171 struct res_rec *answers,
172 struct in_addr from_ip)
174 struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
180 dbgtext( "domain_master_node_status_success:\n" );
181 dbgtext( "Unable to find workgroup " );
182 dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
189 dbgtext( "domain_master_node_status_success:\n" );
190 dbgtext( "Success in node status for workgroup " );
191 dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
194 /* Go through the list of names found at answers->rdata and look for
195 the first SERVER<0x20> name. */
197 if(answers->rdata != NULL)
199 char *p = answers->rdata;
200 int numnames = CVAL(p, 0);
211 name_type = CVAL(p,15);
212 nb_flags = get_nb_flags(&p[16]);
213 trim_string(qname,NULL," ");
217 if(!(nb_flags & NB_GROUP) && (name_type == 0x20))
219 struct nmb_name nmbname;
221 make_nmb_name(&nmbname, qname, name_type);
223 /* Copy the dmb name and IP address
224 into the workgroup struct. */
226 work->dmb_name = nmbname;
227 putip((char *)&work->dmb_addr, &from_ip);
229 /* Do the local master browser announcement to the domain
230 master browser name and IP. */
231 announce_local_master_browser_to_domain_master_browser( work );
233 /* Now synchronise lists with the domain master browser. */
242 dbgtext( "domain_master_node_status_success:\n" );
243 dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
244 dbgtext( "%s.\n", inet_ntoa(from_ip) );
248 /****************************************************************************
249 Function called when a node status query to a domain master browser IP fails.
250 ****************************************************************************/
252 static void domain_master_node_status_fail(struct subnet_record *subrec,
253 struct response_record *rrec)
255 struct userdata_struct *userdata = rrec->userdata;
259 dbgtext( "domain_master_node_status_fail:\n" );
260 dbgtext( "Doing a node status request to the domain master browser\n" );
261 dbgtext( "for workgroup %s ", userdata ? userdata->data : "NULL" );
262 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
263 dbgtext( "Cannot sync browser lists.\n" );
267 /****************************************************************************
268 Function called when a query for a WORKGROUP<1b> name succeeds.
269 ****************************************************************************/
271 static void find_domain_master_name_query_success(struct subnet_record *subrec,
272 struct userdata_struct *userdata_in,
273 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
276 * Unfortunately, finding the IP address of the Domain Master Browser,
277 * as we have here, is not enough. We need to now do a sync to the
278 * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
279 * respond to the SMBSERVER name. To get this name from IP
280 * address we do a Node status request, and look for the first
281 * NAME<0x20> in the response, and take that as the server name.
282 * We also keep a cache of the Domain Master Browser name for this
283 * workgroup in the Workgroup struct, so that if the same IP addess
284 * is returned every time, we don't need to do the node status
288 struct work_record *work;
289 struct nmb_name nmbname;
290 struct userdata_struct *userdata;
291 size_t size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
293 if( !(work = find_workgroup_on_subnet(subrec, q_name->name)) )
297 dbgtext( "find_domain_master_name_query_success:\n" );
298 dbgtext( "Failed to find workgroup %s\n", q_name->name );
303 /* First check if we already have a dmb for this workgroup. */
305 if(!is_zero_ip(work->dmb_addr) && ip_equal(work->dmb_addr, answer_ip))
307 /* Do the local master browser announcement to the domain
308 master browser name and IP. */
309 announce_local_master_browser_to_domain_master_browser( work );
311 /* Now synchronise lists with the domain master browser. */
316 zero_ip(&work->dmb_addr);
318 /* Now initiate the node status request. */
319 make_nmb_name(&nmbname,"*",0x0);
321 /* Put the workgroup name into the userdata so we know
322 what workgroup we're talking to when the reply comes
325 /* Setup the userdata_struct - this is copied so we can use
326 a stack variable for this. */
327 if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
329 DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
333 userdata->copy_fn = NULL;
334 userdata->free_fn = NULL;
335 userdata->userdata_len = strlen(work->work_group)+1;
336 overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
338 node_status( subrec, &nmbname, answer_ip,
339 domain_master_node_status_success,
340 domain_master_node_status_fail,
343 zero_free(userdata, size);
346 /****************************************************************************
347 Function called when a query for a WORKGROUP<1b> name fails.
348 ****************************************************************************/
349 static void find_domain_master_name_query_fail(struct subnet_record *subrec,
350 struct response_record *rrec,
351 struct nmb_name *question_name, int fail_code)
355 dbgtext( "find_domain_master_name_query_fail:\n" );
356 dbgtext( "Unable to find the Domain Master Browser name " );
357 dbgtext( "%s for the workgroup %s.\n",
358 nmb_namestr(question_name), question_name->name );
359 dbgtext( "Unable to sync browse lists in this workgroup.\n" );
363 /****************************************************************************
364 As a local master browser for a workgroup find the domain master browser
365 name, announce ourselves as local master browser to it and then pull the
366 full domain browse lists from it onto the given subnet.
367 **************************************************************************/
369 void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
370 struct work_record *work)
372 struct nmb_name nmbname;
374 /* Only do this if we are using a WINS server. */
375 if(we_are_a_wins_client() == False)
379 dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
380 dbgtext( "Ignoring, as we are not a WINS client.\n" );
385 make_nmb_name(&nmbname,work->work_group,0x1b);
387 /* First, query for the WORKGROUP<1b> name from the WINS server. */
388 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
389 find_domain_master_name_query_success,
390 find_domain_master_name_query_fail,
395 /****************************************************************************
396 Function called when a node status query to a domain master browser IP succeeds.
397 This function is only called on query to a Samba 1.9.18 or above WINS server.
399 Note that adding the workgroup name is enough for this workgroup to be
400 browsable by clients, as clients query the WINS server or broadcast
401 nets for the WORKGROUP<1b> name when they want to browse a workgroup
402 they are not in. We do not need to do a sync with this Domain Master
403 Browser in order for our browse clients to see machines in this workgroup.
405 ****************************************************************************/
407 static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
408 struct userdata_struct *userdata,
409 struct res_rec *answers,
410 struct in_addr from_ip)
412 struct work_record *work;
419 dbgtext( "get_domain_master_name_node_status_success:\n" );
420 dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
424 * Go through the list of names found at answers->rdata and look for
425 * the first WORKGROUP<0x1b> name.
428 if(answers->rdata != NULL)
430 char *p = answers->rdata;
431 int numnames = CVAL(p, 0);
442 name_type = CVAL(p,15);
443 nb_flags = get_nb_flags(&p[16]);
444 trim_string(qname,NULL," ");
448 if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
449 server_name[0] == 0) {
450 /* this is almost certainly the server netbios name */
451 fstrcpy(server_name, qname);
455 if(!(nb_flags & NB_GROUP) && (name_type == 0x1b))
459 dbgtext( "get_domain_master_name_node_status_success:\n" );
460 dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
461 dbgtext( "is a domain master browser for workgroup " );
462 dbgtext( "%s. Adding this name.\n", qname );
466 * If we don't already know about this workgroup, add it
467 * to the workgroup list on the unicast_subnet.
469 if((work = find_workgroup_on_subnet( subrec, qname)) == NULL)
471 struct nmb_name nmbname;
473 * Add it - with an hour in the cache.
475 if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
478 /* remember who the master is */
479 fstrcpy(work->local_master_browser_name, server_name);
480 make_nmb_name(&nmbname, server_name, 0x20);
481 work->dmb_name = nmbname;
482 work->dmb_addr = from_ip;
491 dbgtext( "get_domain_master_name_node_status_success:\n" );
492 dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
493 dbgtext( "%s.\n", inet_ntoa(from_ip) );
497 /****************************************************************************
498 Function called when a node status query to a domain master browser IP fails.
499 ****************************************************************************/
501 static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
502 struct response_record *rrec)
506 dbgtext( "get_domain_master_name_node_status_fail:\n" );
507 dbgtext( "Doing a node status request to the domain master browser " );
508 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
509 dbgtext( "Cannot get workgroup name.\n" );
513 /****************************************************************************
514 Function called when a query for *<1b> name succeeds.
515 ****************************************************************************/
517 static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
518 struct userdata_struct *userdata_in,
519 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
522 * We now have a list of all the domain master browsers for all workgroups
523 * that have registered with the WINS server. Now do a node status request
524 * to each one and look for the first 1b name in the reply. This will be
525 * the workgroup name that we will add to the unicast subnet as a 'non-local'
529 struct nmb_name nmbname;
530 struct in_addr send_ip;
535 dbgtext( "find_all_domain_master_names_query_succes:\n" );
536 dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
537 dbgtext( "IP addresses for Domain Master Browsers.\n" );
540 for(i = 0; i < rrec->rdlength / 6; i++)
542 /* Initiate the node status requests. */
543 make_nmb_name(&nmbname, "*", 0);
545 putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
548 * Don't send node status requests to ourself.
551 if(ismyip( send_ip ))
555 dbgtext( "find_all_domain_master_names_query_succes:\n" );
556 dbgtext( "Not sending node status to our own IP " );
557 dbgtext( "%s.\n", inet_ntoa(send_ip) );
564 dbgtext( "find_all_domain_master_names_query_success:\n" );
565 dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
568 node_status( subrec, &nmbname, send_ip,
569 get_domain_master_name_node_status_success,
570 get_domain_master_name_node_status_fail,
575 /****************************************************************************
576 Function called when a query for *<1b> name fails.
577 ****************************************************************************/
578 static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
579 struct response_record *rrec,
580 struct nmb_name *question_name, int fail_code)
584 dbgtext( "find_domain_master_name_query_fail:\n" );
585 dbgtext( "WINS server did not reply to a query for name " );
586 dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
587 dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
591 /****************************************************************************
592 If we are a domain master browser on the unicast subnet, do a query to the
593 WINS server for the *<1b> name. This will only work to a Samba WINS server,
594 so ignore it if we fail. If we succeed, contact each of the IP addresses in
595 turn and do a node status request to them. If this succeeds then look for a
596 <1b> name in the reply - this is the workgroup name. Add this to the unicast
597 subnet. This is expensive, so we only do this every 15 minutes.
598 **************************************************************************/
599 void collect_all_workgroup_names_from_wins_server(time_t t)
601 static time_t lastrun = 0;
602 struct work_record *work;
603 struct nmb_name nmbname;
605 /* Only do this if we are using a WINS server. */
606 if(we_are_a_wins_client() == False)
609 /* Check to see if we are a domain master browser on the unicast subnet. */
610 if((work = find_workgroup_on_subnet( unicast_subnet, lp_workgroup())) == NULL)
614 dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
615 dbgtext( "Cannot find my workgroup %s ", lp_workgroup() );
616 dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
621 if(!AM_DOMAIN_MASTER_BROWSER(work))
624 if ((lastrun != 0) && (t < lastrun + (15 * 60)))
629 make_nmb_name(&nmbname,"*",0x1b);
631 /* First, query for the *<1b> name from the WINS server. */
632 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
633 find_all_domain_master_names_query_success,
634 find_all_domain_master_names_query_fail,
639 /****************************************************************************
640 If we are a domain master browser on the unicast subnet, do a regular sync
641 with all other DMBs that we know of on that subnet.
643 To prevent exponential network traffic with large numbers of workgroups
644 we use a randomised system where sync probability is inversely proportional
645 to the number of known workgroups
646 **************************************************************************/
647 void sync_all_dmbs(time_t t)
649 static time_t lastrun = 0;
650 struct work_record *work;
653 /* Only do this if we are using a WINS server. */
654 if(we_are_a_wins_client() == False)
657 /* Check to see if we are a domain master browser on the
659 work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup());
662 if (!AM_DOMAIN_MASTER_BROWSER(work))
665 if ((lastrun != 0) && (t < lastrun + (5 * 60)))
668 /* count how many syncs we might need to do */
669 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
670 if (strcmp(lp_workgroup(), work->work_group)) {
675 /* sync with a probability of 1/count */
676 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
677 if (strcmp(lp_workgroup(), work->work_group)) {
678 if (((unsigned)sys_random()) % count != 0) continue;
682 if (!work->dmb_name.name[0]) {
683 /* we don't know the DMB - assume it is
684 the same as the unicast local master */
685 make_nmb_name(&work->dmb_name,
686 work->local_master_browser_name,
690 DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
692 inet_ntoa(work->dmb_addr)));
693 sync_browse_lists(work,
695 work->dmb_name.name_type,
696 work->dmb_addr, False, False);