2 Unix SMB/Netbios implementation.
4 NBT netbios routines and daemon - version 2
5 Copyright (C) Andrew Tridgell 1994-1998
6 Copyright (C) Luke Kenneth Casson Leighton 1994-1998
7 Copyright (C) Jeremy Allison 1994-1998
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
28 extern int DEBUGLEVEL;
30 extern struct in_addr ipzero;
31 extern pstring global_myname;
32 extern fstring global_myworkgroup;
34 /* This is our local master browser list database. */
35 extern ubi_dlList lmb_browserlist[];
37 /****************************************************************************
38 As a domain master browser, do a sync with a local master browser.
39 **************************************************************************/
40 static void sync_with_lmb(struct browse_cache_record *browc)
42 struct work_record *work;
44 if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) )
48 dbgtext( "sync_with_lmb:\n" );
49 dbgtext( "Failed to get a workgroup for a local master browser " );
50 dbgtext( "cache entry workgroup " );
51 dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
56 /* We should only be doing this if we are a domain master browser for
57 the given workgroup. Ensure this is so. */
59 if(!AM_DOMAIN_MASTER_BROWSER(work))
63 dbgtext( "sync_with_lmb:\n" );
64 dbgtext( "We are trying to sync with a local master browser " );
65 dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
66 dbgtext( "and we are not a domain master browser on this workgroup.\n" );
67 dbgtext( "Error!\n" );
74 dbgtext( "sync_with_lmb:\n" );
75 dbgtext( "Initiating sync with local master browser " );
76 dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
77 dbgtext( "for workgroup %s\n", browc->work_group );
80 sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
82 browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
85 /****************************************************************************
86 Sync or expire any local master browsers.
87 **************************************************************************/
88 void dmb_expire_and_sync_browser_lists(time_t t)
90 static time_t last_run = 0;
91 struct browse_cache_record *browc;
93 /* Only do this every 20 seconds. */
94 if (t - last_run < 20)
99 expire_lmb_browsers(t);
101 for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
103 browc = (struct browse_cache_record *)ubi_dlNext( browc ) )
105 if (browc->sync_time < t)
106 sync_with_lmb(browc);
110 /****************************************************************************
111 As a local master browser, send an announce packet to the domain master browser.
112 **************************************************************************/
114 static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
119 if(ismyip(work->dmb_addr))
123 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
124 dbgtext( "We are both a domain and a local master browser for " );
125 dbgtext( "workgroup %s. ", work->work_group );
126 dbgtext( "Do not announce to ourselves.\n" );
131 memset(outbuf,'\0',sizeof(outbuf));
133 CVAL(p,0) = ANN_MasterAnnouncement;
136 StrnCpy(p,global_myname,15);
138 p = skip_string(p,1);
142 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
143 dbgtext( "Sending local master announce to " );
144 dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
148 send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
149 global_myname, 0x0, work->dmb_name.name, 0x0,
150 work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
154 /****************************************************************************
155 As a local master browser, do a sync with a domain master browser.
156 **************************************************************************/
158 static void sync_with_dmb(struct work_record *work)
162 dbgtext( "sync_with_dmb:\n" );
163 dbgtext( "Initiating sync with domain master browser " );
164 dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
165 dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
166 dbgtext( "for workgroup %s\n", work->work_group );
169 sync_browse_lists(work, work->dmb_name.name, work->dmb_name.name_type,
170 work->dmb_addr, False, True);
173 /****************************************************************************
174 Function called when a node status query to a domain master browser IP succeeds.
175 ****************************************************************************/
177 static void domain_master_node_status_success(struct subnet_record *subrec,
178 struct userdata_struct *userdata,
179 struct res_rec *answers,
180 struct in_addr from_ip)
182 struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
188 dbgtext( "domain_master_node_status_success:\n" );
189 dbgtext( "Unable to find workgroup " );
190 dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
197 dbgtext( "domain_master_node_status_success:\n" );
198 dbgtext( "Success in node status for workgroup " );
199 dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
202 /* Go through the list of names found at answers->rdata and look for
203 the first SERVER<0x20> name. */
205 if(answers->rdata != NULL)
207 char *p = answers->rdata;
208 int numnames = CVAL(p, 0);
219 name_type = CVAL(p,15);
220 nb_flags = get_nb_flags(&p[16]);
221 trim_string(qname,NULL," ");
225 if(!(nb_flags & NB_GROUP) && (name_type == 0x20))
227 struct nmb_name nmbname;
229 make_nmb_name(&nmbname, qname, name_type, scope);
231 /* Copy the dmb name and IP address
232 into the workgroup struct. */
234 work->dmb_name = nmbname;
235 putip((char *)&work->dmb_addr, &from_ip);
237 /* Do the local master browser announcement to the domain
238 master browser name and IP. */
239 announce_local_master_browser_to_domain_master_browser( work );
241 /* Now synchronise lists with the domain master browser. */
250 dbgtext( "domain_master_node_status_success:\n" );
251 dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
252 dbgtext( "%s.\n", inet_ntoa(from_ip) );
256 /****************************************************************************
257 Function called when a node status query to a domain master browser IP fails.
258 ****************************************************************************/
260 static void domain_master_node_status_fail(struct subnet_record *subrec,
261 struct response_record *rrec)
263 struct userdata_struct *userdata = rrec->userdata;
267 dbgtext( "domain_master_node_status_fail:\n" );
268 dbgtext( "Doing a node status request to the domain master browser\n" );
269 dbgtext( "for workgroup %s ", userdata->data );
270 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
271 dbgtext( "Cannot sync browser lists.\n" );
275 /****************************************************************************
276 Function called when a query for a WORKGROUP<1b> name succeeds.
277 ****************************************************************************/
279 static void find_domain_master_name_query_success(struct subnet_record *subrec,
280 struct userdata_struct *userdata_in,
281 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
284 * Unfortunately, finding the IP address of the Domain Master Browser,
285 * as we have here, is not enough. We need to now do a sync to the
286 * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
287 * respond to the SMBSERVER name. To get this name from IP
288 * address we do a Node status request, and look for the first
289 * NAME<0x20> in the response, and take that as the server name.
290 * We also keep a cache of the Domain Master Browser name for this
291 * workgroup in the Workgroup struct, so that if the same IP addess
292 * is returned every time, we don't need to do the node status
296 struct work_record *work;
297 struct nmb_name nmbname;
298 struct userdata_struct *userdata;
299 int size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
301 if( !(work = find_workgroup_on_subnet(subrec, q_name->name)) )
305 dbgtext( "find_domain_master_name_query_success:\n" );
306 dbgtext( "Failed to find workgroup %s\n", q_name->name );
311 /* First check if we already have a dmb for this workgroup. */
313 if(!ip_equal(work->dmb_addr, ipzero) && ip_equal(work->dmb_addr, answer_ip))
315 /* Do the local master browser announcement to the domain
316 master browser name and IP. */
317 announce_local_master_browser_to_domain_master_browser( work );
319 /* Now synchronise lists with the domain master browser. */
324 putip((char *)&work->dmb_addr, &ipzero);
326 /* Now initiate the node status request. */
327 memset((char *)&nmbname, '\0',sizeof(nmbname));
328 nmbname.name[0] = '*';
330 /* Put the workgroup name into the userdata so we know
331 what workgroup we're talking to when the reply comes
334 /* Setup the userdata_struct - this is copied so we can use
335 a stack variable for this. */
336 if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
338 DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
342 userdata->copy_fn = NULL;
343 userdata->free_fn = NULL;
344 userdata->userdata_len = strlen(work->work_group)+1;
345 pstrcpy(userdata->data, work->work_group);
347 node_status( subrec, &nmbname, answer_ip,
348 domain_master_node_status_success,
349 domain_master_node_status_fail,
352 zero_free(userdata, size);
355 /****************************************************************************
356 Function called when a query for a WORKGROUP<1b> name fails.
357 ****************************************************************************/
358 static void find_domain_master_name_query_fail(struct subnet_record *subrec,
359 struct response_record *rrec,
360 struct nmb_name *question_name, int fail_code)
364 dbgtext( "find_domain_master_name_query_fail:\n" );
365 dbgtext( "Unable to find the Domain Master Browser name " );
366 dbgtext( "%s for the workgroup %s.\n",
367 nmb_namestr(question_name), question_name->name );
368 dbgtext( "Unable to sync browse lists in this workgroup.\n" );
372 /****************************************************************************
373 As a local master browser for a workgroup find the domain master browser
374 name, announce ourselves as local master browser to it and then pull the
375 full domain browse lists from it onto the given subnet.
376 **************************************************************************/
378 void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
379 struct work_record *work)
381 struct nmb_name nmbname;
383 /* Only do this if we are using a WINS server. */
384 if(we_are_a_wins_client() == False)
388 dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
389 dbgtext( "Ignoring, as we are not a WINS client.\n" );
394 make_nmb_name(&nmbname,work->work_group,0x1b,scope);
396 /* First, query for the WORKGROUP<1b> name from the WINS server. */
397 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
398 find_domain_master_name_query_success,
399 find_domain_master_name_query_fail,
404 /****************************************************************************
405 Function called when a node status query to a domain master browser IP succeeds.
406 This function is only called on query to a Samba 1.9.18 or above WINS server.
408 Note that adding the workgroup name is enough for this workgroup to be
409 browsable by clients, as clients query the WINS server or broadcast
410 nets for the WORKGROUP<1b> name when they want to browse a workgroup
411 they are not in. We do not need to do a sync with this Domain Master
412 Browser in order for our browse clients to see machines in this workgroup.
414 ****************************************************************************/
416 static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
417 struct userdata_struct *userdata,
418 struct res_rec *answers,
419 struct in_addr from_ip)
421 struct work_record *work;
428 dbgtext( "get_domain_master_name_node_status_success:\n" );
429 dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
433 * Go through the list of names found at answers->rdata and look for
434 * the first WORKGROUP<0x1b> name.
437 if(answers->rdata != NULL)
439 char *p = answers->rdata;
440 int numnames = CVAL(p, 0);
451 name_type = CVAL(p,15);
452 nb_flags = get_nb_flags(&p[16]);
453 trim_string(qname,NULL," ");
457 if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
458 server_name[0] == 0) {
459 /* this is almost certainly the server netbios name */
460 fstrcpy(server_name, qname);
464 if(!(nb_flags & NB_GROUP) && (name_type == 0x1b))
468 dbgtext( "get_domain_master_name_node_status_success:\n" );
469 dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
470 dbgtext( "is a domain master browser for workgroup " );
471 dbgtext( "%s. Adding this name.\n", qname );
475 * If we don't already know about this workgroup, add it
476 * to the workgroup list on the unicast_subnet.
478 if((work = find_workgroup_on_subnet( subrec, qname)) == NULL)
480 struct nmb_name nmbname;
482 * Add it - with an hour in the cache.
484 if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
487 /* remember who the master is */
488 fstrcpy(work->local_master_browser_name, server_name);
489 make_nmb_name(&nmbname, server_name, 0x20, scope);
490 work->dmb_name = nmbname;
491 work->dmb_addr = from_ip;
500 dbgtext( "get_domain_master_name_node_status_success:\n" );
501 dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
502 dbgtext( "%s.\n", inet_ntoa(from_ip) );
506 /****************************************************************************
507 Function called when a node status query to a domain master browser IP fails.
508 ****************************************************************************/
510 static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
511 struct response_record *rrec)
515 dbgtext( "get_domain_master_name_node_status_fail:\n" );
516 dbgtext( "Doing a node status request to the domain master browser " );
517 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
518 dbgtext( "Cannot get workgroup name.\n" );
522 /****************************************************************************
523 Function called when a query for *<1b> name succeeds.
524 ****************************************************************************/
526 static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
527 struct userdata_struct *userdata_in,
528 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
531 * We now have a list of all the domain master browsers for all workgroups
532 * that have registered with the WINS server. Now do a node status request
533 * to each one and look for the first 1b name in the reply. This will be
534 * the workgroup name that we will add to the unicast subnet as a 'non-local'
538 struct nmb_name nmbname;
539 struct in_addr send_ip;
544 dbgtext( "find_all_domain_master_names_query_succes:\n" );
545 dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
546 dbgtext( "IP addresses for Domain Master Browsers.\n" );
549 for(i = 0; i < rrec->rdlength / 6; i++)
551 /* Initiate the node status requests. */
552 memset((char *)&nmbname, '\0', sizeof(nmbname));
553 nmbname.name[0] = '*';
555 putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
558 * Don't send node status requests to ourself.
561 if(ismyip( send_ip ))
565 dbgtext( "find_all_domain_master_names_query_succes:\n" );
566 dbgtext( "Not sending node status to our own IP " );
567 dbgtext( "%s.\n", inet_ntoa(send_ip) );
574 dbgtext( "find_all_domain_master_names_query_success:\n" );
575 dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
578 node_status( subrec, &nmbname, send_ip,
579 get_domain_master_name_node_status_success,
580 get_domain_master_name_node_status_fail,
585 /****************************************************************************
586 Function called when a query for *<1b> name fails.
587 ****************************************************************************/
588 static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
589 struct response_record *rrec,
590 struct nmb_name *question_name, int fail_code)
594 dbgtext( "find_domain_master_name_query_fail:\n" );
595 dbgtext( "WINS server did not reply to a query for name " );
596 dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
597 dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
601 /****************************************************************************
602 If we are a domain master browser on the unicast subnet, do a query to the
603 WINS server for the *<1b> name. This will only work to a Samba WINS server,
604 so ignore it if we fail. If we succeed, contact each of the IP addresses in
605 turn and do a node status request to them. If this succeeds then look for a
606 <1b> name in the reply - this is the workgroup name. Add this to the unicast
607 subnet. This is expensive, so we only do this every 15 minutes.
608 **************************************************************************/
609 void collect_all_workgroup_names_from_wins_server(time_t t)
611 static time_t lastrun = 0;
612 struct work_record *work;
613 struct nmb_name nmbname;
615 /* Only do this if we are using a WINS server. */
616 if(we_are_a_wins_client() == False)
619 /* Check to see if we are a domain master browser on the unicast subnet. */
620 if((work = find_workgroup_on_subnet( unicast_subnet, global_myworkgroup)) == NULL)
624 dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
625 dbgtext( "Cannot find my workgroup %s ", global_myworkgroup );
626 dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
631 if(!AM_DOMAIN_MASTER_BROWSER(work))
634 if ((lastrun != 0) && (t < lastrun + (15 * 60)))
639 make_nmb_name(&nmbname,"*",0x1b,scope);
641 /* First, query for the *<1b> name from the WINS server. */
642 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
643 find_all_domain_master_names_query_success,
644 find_all_domain_master_names_query_fail,
649 /****************************************************************************
650 If we are a domain master browser on the unicast subnet, do a regular sync
651 with all other DMBs that we know of on that subnet.
653 To prevent exponential network traffic with large numbers of workgroups
654 we use a randomised system where sync probability is inversely proportional
655 to the number of known workgroups
656 **************************************************************************/
657 void sync_all_dmbs(time_t t)
659 static time_t lastrun = 0;
660 struct work_record *work;
663 /* Only do this if we are using a WINS server. */
664 if(we_are_a_wins_client() == False)
667 /* Check to see if we are a domain master browser on the
669 work = find_workgroup_on_subnet(unicast_subnet, global_myworkgroup);
672 if (!AM_DOMAIN_MASTER_BROWSER(work))
675 if ((lastrun != 0) && (t < lastrun + (5 * 60)))
678 /* count how many syncs we might need to do */
679 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
680 if (strcmp(global_myworkgroup, work->work_group)) {
685 /* sync with a probability of 1/count */
686 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
687 if (strcmp(global_myworkgroup, work->work_group)) {
688 if (((unsigned)sys_random()) % count != 0) continue;
692 if (!work->dmb_name.name[0]) {
693 /* we don't know the DMB - assume it is
694 the same as the unicast local master */
695 make_nmb_name(&work->dmb_name,
696 work->local_master_browser_name,
700 DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
702 inet_ntoa(work->dmb_addr)));
703 sync_browse_lists(work,
705 work->dmb_name.name_type,
706 work->dmb_addr, False, False);