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 struct 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))) {
45 DEBUG(0, ("sync_with_lmb: failed to get a \
46 workgroup for a local master browser cache entry workgroup %s, server %s\n",
47 browc->work_group, browc->lmb_name));
51 /* We should only be doing this if we are a domain master browser for
52 the given workgroup. Ensure this is so. */
54 if(!AM_DOMAIN_MASTER_BROWSER(work))
56 DEBUG(0,("sync_with_lmb: We are trying to sync with a local master browser %s \
57 for workgroup %s and we are not a domain master browser on this workgroup. Error !\n",
58 browc->lmb_name, browc->work_group));
62 DEBUG(2, ("sync_with_lmb: Initiating sync with local master browser %s<0x20> at IP %s for \
63 workgroup %s\n", browc->lmb_name, inet_ntoa(browc->ip), browc->work_group));
65 sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
67 browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
70 /****************************************************************************
71 Sync or expire any local master browsers.
72 **************************************************************************/
73 void dmb_expire_and_sync_browser_lists(time_t t)
75 static time_t last_run = 0;
76 struct browse_cache_record *browc;
78 /* Only do this every 20 seconds. */
79 if (t - last_run < 20)
84 expire_lmb_browsers(t);
86 for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
88 browc = (struct browse_cache_record *)ubi_dlNext( browc ) )
90 if (browc->sync_time < t)
95 /****************************************************************************
96 As a local master browser, send an announce packet to the domain master browser.
97 **************************************************************************/
99 static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
104 if(ismyip(work->dmb_addr))
106 DEBUG(2,("announce_local_master_browser_to_domain_master_browser: We are both a domain \
107 and a local master browser for workgroup %s. \
108 Do not announce to ourselves.\n", work->work_group ));
112 bzero(outbuf,sizeof(outbuf));
114 CVAL(p,0) = ANN_MasterAnnouncement;
117 StrnCpy(p,global_myname,15);
119 p = skip_string(p,1);
121 DEBUG(4,("announce_local_master_browser_to_domain_master_browser: Sending local master announce \
122 to %s for workgroup %s.\n", namestr(&work->dmb_name), work->work_group ));
124 send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
125 global_myname, 0x0, work->dmb_name.name, 0x0,
126 work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
130 /****************************************************************************
131 As a local master browser, do a sync with a domain master browser.
132 **************************************************************************/
134 static void sync_with_dmb(struct work_record *work)
136 DEBUG(2, ("sync_with_dmb: Initiating sync with domain master browser %s at IP %s for \
137 workgroup %s\n", namestr(&work->dmb_name), inet_ntoa(work->dmb_addr), work->work_group));
139 sync_browse_lists(work, work->dmb_name.name, work->dmb_name.name_type,
140 work->dmb_addr, False, True);
143 /****************************************************************************
144 Function called when a node status query to a domain master browser IP succeeds.
145 ****************************************************************************/
147 static void domain_master_node_status_success(struct subnet_record *subrec,
148 struct userdata_struct *userdata,
149 struct res_rec *answers,
150 struct in_addr from_ip)
152 struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
156 DEBUG(0,("domain_master_node_status_success: Unable to find workgroup %s on subnet %s.\n",
157 userdata->data, subrec->subnet_name));
161 DEBUG(3,("domain_master_node_status_success: Success in node status for workgroup %s from ip %s\n",
162 work->work_group, inet_ntoa(from_ip) ));
164 /* Go through the list of names found at answers->rdata and look for
165 the first SERVER<0x20> name. */
167 if(answers->rdata != NULL)
169 char *p = answers->rdata;
170 int numnames = CVAL(p, 0);
181 name_type = CVAL(p,15);
182 nb_flags = get_nb_flags(&p[16]);
183 trim_string(qname,NULL," ");
187 if(!(nb_flags & NB_GROUP) && (name_type == 0x20))
189 struct nmb_name nmbname;
191 make_nmb_name(&nmbname, qname, name_type, scope);
193 /* Copy the dmb name and IP address
194 into the workgroup struct. */
196 work->dmb_name = nmbname;
197 putip((char *)&work->dmb_addr, &from_ip);
199 /* Do the local master browser announcement to the domain
200 master browser name and IP. */
201 announce_local_master_browser_to_domain_master_browser( work );
203 /* Now synchronise lists with the domain master browser. */
210 DEBUG(0,("domain_master_node_status_success: Failed to find a SERVER<0x20> \
211 name in reply from IP %s.\n", inet_ntoa(from_ip) ));
214 /****************************************************************************
215 Function called when a node status query to a domain master browser IP fails.
216 ****************************************************************************/
218 static void domain_master_node_status_fail(struct subnet_record *subrec,
219 struct response_record *rrec)
221 struct userdata_struct *userdata = rrec->userdata;
223 DEBUG(0,("domain_master_node_status_fail: Doing a node status request to \
224 the domain master browser for workgroup %s at IP %s failed. Cannot sync browser \
225 lists.\n", userdata->data, inet_ntoa(rrec->packet->ip) ));
229 /****************************************************************************
230 Function called when a query for a WORKGROUP<1b> name succeeds.
231 ****************************************************************************/
233 static void find_domain_master_name_query_success(struct subnet_record *subrec,
234 struct userdata_struct *userdata_in,
235 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
238 * Unfortunately, finding the IP address of the Domain Master Browser,
239 * as we have here, is not enough. We need to now do a sync to the
240 * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
241 * respond to the SMBSERVER name. To get this name from IP
242 * address we do a Node status request, and look for the first
243 * NAME<0x20> in the response, and take that as the server name.
244 * We also keep a cache of the Domain Master Browser name for this
245 * workgroup in the Workgroup struct, so that if the same IP addess
246 * is returned every time, we don't need to do the node status
250 struct work_record *work;
251 struct nmb_name nmbname;
252 struct userdata_struct *userdata;
253 int size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
255 if (!(work = find_workgroup_on_subnet(subrec, q_name->name))) {
256 DEBUG(0, ("find_domain_master_name_query_success: failed to find \
257 workgroup %s\n", q_name->name ));
261 /* First check if we already have a dmb for this workgroup. */
263 if(!ip_equal(work->dmb_addr, ipzero) && ip_equal(work->dmb_addr, answer_ip))
265 /* Do the local master browser announcement to the domain
266 master browser name and IP. */
267 announce_local_master_browser_to_domain_master_browser( work );
269 /* Now synchronise lists with the domain master browser. */
274 putip((char *)&work->dmb_addr, &ipzero);
276 /* Now initiate the node status request. */
277 bzero((char *)&nmbname, sizeof(nmbname));
278 nmbname.name[0] = '*';
280 /* Put the workgroup name into the userdata so we know
281 what workgroup we're talking to when the reply comes
284 /* Setup the userdata_struct - this is copied so we can use
285 a stack variable for this. */
286 if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
288 DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
292 userdata->copy_fn = NULL;
293 userdata->free_fn = NULL;
294 userdata->userdata_len = strlen(work->work_group)+1;
295 pstrcpy(userdata->data, work->work_group);
297 node_status( subrec, &nmbname, answer_ip,
298 domain_master_node_status_success,
299 domain_master_node_status_fail,
302 zero_free(userdata, size);
305 /****************************************************************************
306 Function called when a query for a WORKGROUP<1b> name fails.
307 ****************************************************************************/
308 static void find_domain_master_name_query_fail(struct subnet_record *subrec,
309 struct response_record *rrec,
310 struct nmb_name *question_name, int fail_code)
312 DEBUG(0,("find_domain_master_name_query_fail: Unable to find the Domain Master \
313 Browser name %s for the workgroup %s. Unable to sync browse lists in this workgroup.\n",
314 namestr(question_name), question_name->name ));
317 /****************************************************************************
318 As a local master browser for a workgroup find the domain master browser
319 name, announce ourselves as local master browser to it and then pull the
320 full domain browse lists from it onto the given subnet.
321 **************************************************************************/
323 void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
324 struct work_record *work)
326 struct nmb_name nmbname;
328 /* Only do this if we are using a WINS server. */
329 if(we_are_a_wins_client() == False)
331 DEBUG(10,("announce_and_sync_with_domain_master_browser: Ignoring as we are not a WINS client.\n"));
335 make_nmb_name(&nmbname,work->work_group,0x1b,scope);
337 /* First, query for the WORKGROUP<1b> name from the WINS server. */
338 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
339 find_domain_master_name_query_success,
340 find_domain_master_name_query_fail,
345 /****************************************************************************
346 Function called when a node status query to a domain master browser IP succeeds.
347 This function is only called on query to a Samba 1.9.18 or above WINS server.
349 Note that adding the workgroup name is enough for this workgroup to be
350 browsable by clients, as clients query the WINS server or broadcast
351 nets for the WORKGROUP<1b> name when they want to browse a workgroup
352 they are not in. We do not need to do a sync with this Domain Master
353 Browser in order for our browse clients to see machines in this workgroup.
355 ****************************************************************************/
357 static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
358 struct userdata_struct *userdata,
359 struct res_rec *answers,
360 struct in_addr from_ip)
362 struct work_record *work;
367 DEBUG(3,("get_domain_master_name_node_status_success: Success in node status from ip %s\n",
368 inet_ntoa(from_ip) ));
371 * Go through the list of names found at answers->rdata and look for
372 * the first WORKGROUP<0x1b> name.
375 if(answers->rdata != NULL)
377 char *p = answers->rdata;
378 int numnames = CVAL(p, 0);
389 name_type = CVAL(p,15);
390 nb_flags = get_nb_flags(&p[16]);
391 trim_string(qname,NULL," ");
395 if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
396 server_name[0] == 0) {
397 /* this is almost certainly the server netbios name */
398 fstrcpy(server_name, qname);
402 if(!(nb_flags & NB_GROUP) && (name_type == 0x1b))
405 DEBUG(5,("get_domain_master_name_node_status_success: %s(%s) is a domain \
406 master browser for workgroup %s. Adding this name.\n",
407 server_name, inet_ntoa(from_ip), qname ));
410 * If we don't already know about this workgroup, add it
411 * to the workgroup list on the unicast_subnet.
413 if((work = find_workgroup_on_subnet( subrec, qname)) == NULL)
415 struct nmb_name nmbname;
417 * Add it - with an hour in the cache.
419 if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
422 /* remember who the master is */
423 fstrcpy(work->local_master_browser_name, server_name);
424 make_nmb_name(&nmbname, server_name, 0x20, scope);
425 work->dmb_name = nmbname;
426 work->dmb_addr = from_ip;
433 DEBUG(0,("get_domain_master_name_node_status_success: Failed to find a WORKGROUP<0x1b> \
434 name in reply from IP %s.\n", inet_ntoa(from_ip) ));
437 /****************************************************************************
438 Function called when a node status query to a domain master browser IP fails.
439 ****************************************************************************/
441 static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
442 struct response_record *rrec)
444 DEBUG(0,("get_domain_master_name_node_status_fail: Doing a node status request to \
445 the domain master browser at IP %s failed. Cannot get workgroup name.\n",
446 inet_ntoa(rrec->packet->ip) ));
449 /****************************************************************************
450 Function called when a query for *<1b> name succeeds.
451 ****************************************************************************/
453 static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
454 struct userdata_struct *userdata_in,
455 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
458 * We now have a list of all the domain master browsers for all workgroups
459 * that have registered with the WINS server. Now do a node status request
460 * to each one and look for the first 1b name in the reply. This will be
461 * the workgroup name that we will add to the unicast subnet as a 'non-local'
465 struct nmb_name nmbname;
466 struct in_addr send_ip;
469 DEBUG(5,("find_all_domain_master_names_query_succes: Got answer from WINS server of %d \
470 IP addresses for Domain Master Browsers.\n", rrec->rdlength / 6 ));
472 for(i = 0; i < rrec->rdlength / 6; i++)
474 /* Initiate the node status requests. */
475 bzero((char *)&nmbname, sizeof(nmbname));
476 nmbname.name[0] = '*';
478 putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
481 * Don't send node status requests to ourself.
484 if(ismyip( send_ip ))
486 DEBUG(5,("find_all_domain_master_names_query_succes: Not sending node status \
487 to our own IP %s.\n", inet_ntoa(send_ip) ));
491 DEBUG(5,("find_all_domain_master_names_query_succes: sending node status request to \
492 IP %s.\n", inet_ntoa(send_ip) ));
494 node_status( subrec, &nmbname, send_ip,
495 get_domain_master_name_node_status_success,
496 get_domain_master_name_node_status_fail,
501 /****************************************************************************
502 Function called when a query for *<1b> name fails.
503 ****************************************************************************/
504 static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
505 struct response_record *rrec,
506 struct nmb_name *question_name, int fail_code)
508 DEBUG(10,("find_domain_master_name_query_fail: WINS server did not reply to a query \
509 for name %s. This means it is probably not a Samba 1.9.18 or above WINS server.\n",
510 namestr(question_name) ));
513 /****************************************************************************
514 If we are a domain master browser on the unicast subnet, do a query to the
515 WINS server for the *<1b> name. This will only work to a Samba WINS server,
516 so ignore it if we fail. If we succeed, contact each of the IP addresses in
517 turn and do a node status request to them. If this succeeds then look for a
518 <1b> name in the reply - this is the workgroup name. Add this to the unicast
519 subnet. This is expensive, so we only do this every 15 minutes.
520 **************************************************************************/
521 void collect_all_workgroup_names_from_wins_server(time_t t)
523 static time_t lastrun = 0;
524 struct work_record *work;
525 struct nmb_name nmbname;
527 /* Only do this if we are using a WINS server. */
528 if(we_are_a_wins_client() == False)
531 /* Check to see if we are a domain master browser on the unicast subnet. */
532 if((work = find_workgroup_on_subnet( unicast_subnet, global_myworkgroup)) == NULL)
534 DEBUG(0,("collect_all_workgroup_names_from_wins_server: Cannot find my workgroup %s on subnet %s.\n",
535 global_myworkgroup, unicast_subnet->subnet_name ));
539 if(!AM_DOMAIN_MASTER_BROWSER(work))
542 if ((lastrun != 0) && (t < lastrun + (15 * 60)))
547 make_nmb_name(&nmbname,"*",0x1b,scope);
549 /* First, query for the *<1b> name from the WINS server. */
550 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
551 find_all_domain_master_names_query_success,
552 find_all_domain_master_names_query_fail,
557 /****************************************************************************
558 If we are a domain master browser on the unicast subnet, do a regular sync
559 with all other DMBs that we know of on that subnet.
561 To prevent exponential network traffic with large numbers of workgroups
562 we use a randomised system where sync probability is inversely proportional
563 to the number of known workgroups
564 **************************************************************************/
565 void sync_all_dmbs(time_t t)
567 static time_t lastrun = 0;
568 struct work_record *work;
571 /* Only do this if we are using a WINS server. */
572 if(we_are_a_wins_client() == False)
575 /* Check to see if we are a domain master browser on the
577 work = find_workgroup_on_subnet(unicast_subnet, global_myworkgroup);
580 if (!AM_DOMAIN_MASTER_BROWSER(work))
583 if ((lastrun != 0) && (t < lastrun + (5 * 60)))
586 /* count how many syncs we might need to do */
587 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
588 if (strcmp(global_myworkgroup, work->work_group)) {
593 /* sync with a probability of 1/count */
594 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
595 if (strcmp(global_myworkgroup, work->work_group)) {
596 if (((unsigned)sys_random()) % count != 0) continue;
600 if (!work->dmb_name.name[0]) {
601 /* we don't know the DMB - assume it is
602 the same as the unicast local master */
603 make_nmb_name(&work->dmb_name,
604 work->local_master_browser_name,
608 DEBUG(3,("initiating DMB<->DMB sync with %s(%s)\n",
610 inet_ntoa(work->dmb_addr)));
611 sync_browse_lists(work,
613 work->dmb_name.name_type,
614 work->dmb_addr, False, False);