dnscrypto-proxy: Support files updated.
[tomato.git] / release / src / router / samba / source / nmbd / nmbd_browsesync.c
blob28be3606759bfcb1f869eb47d7f7f9acc360be86
1 /*
2 Unix SMB/Netbios implementation.
3 Version 1.9.
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.
25 #include "includes.h"
26 #include "smb.h"
28 extern int DEBUGLEVEL;
29 extern struct in_addr ipzero;
30 extern pstring global_myname;
31 extern fstring global_myworkgroup;
33 /* This is our local master browser list database. */
34 extern ubi_dlList lmb_browserlist[];
36 /****************************************************************************
37 As a domain master browser, do a sync with a local master browser.
38 **************************************************************************/
39 static void sync_with_lmb(struct browse_cache_record *browc)
41 struct work_record *work;
43 if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) )
45 if( DEBUGLVL( 0 ) )
47 dbgtext( "sync_with_lmb:\n" );
48 dbgtext( "Failed to get a workgroup for a local master browser " );
49 dbgtext( "cache entry workgroup " );
50 dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
52 return;
55 /* We should only be doing this if we are a domain master browser for
56 the given workgroup. Ensure this is so. */
58 if(!AM_DOMAIN_MASTER_BROWSER(work))
60 if( DEBUGLVL( 0 ) )
62 dbgtext( "sync_with_lmb:\n" );
63 dbgtext( "We are trying to sync with a local master browser " );
64 dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
65 dbgtext( "and we are not a domain master browser on this workgroup.\n" );
66 dbgtext( "Error!\n" );
68 return;
71 if( DEBUGLVL( 2 ) )
73 dbgtext( "sync_with_lmb:\n" );
74 dbgtext( "Initiating sync with local master browser " );
75 dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
76 dbgtext( "for workgroup %s\n", browc->work_group );
79 sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
81 browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
84 /****************************************************************************
85 Sync or expire any local master browsers.
86 **************************************************************************/
87 void dmb_expire_and_sync_browser_lists(time_t t)
89 static time_t last_run = 0;
90 struct browse_cache_record *browc;
92 /* Only do this every 20 seconds. */
93 if (t - last_run < 20)
94 return;
96 last_run = t;
98 expire_lmb_browsers(t);
100 for( browc = (struct browse_cache_record *)ubi_dlFirst( lmb_browserlist );
101 browc;
102 browc = (struct browse_cache_record *)ubi_dlNext( browc ) )
104 if (browc->sync_time < t)
105 sync_with_lmb(browc);
109 /****************************************************************************
110 As a local master browser, send an announce packet to the domain master browser.
111 **************************************************************************/
113 static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
115 pstring outbuf;
116 char *p;
118 if(ismyip(work->dmb_addr))
120 if( DEBUGLVL( 2 ) )
122 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
123 dbgtext( "We are both a domain and a local master browser for " );
124 dbgtext( "workgroup %s. ", work->work_group );
125 dbgtext( "Do not announce to ourselves.\n" );
127 return;
130 memset(outbuf,'\0',sizeof(outbuf));
131 p = outbuf;
132 CVAL(p,0) = ANN_MasterAnnouncement;
133 p++;
135 StrnCpy(p,global_myname,15);
136 strupper(p);
137 p = skip_string(p,1);
139 if( DEBUGLVL( 4 ) )
141 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
142 dbgtext( "Sending local master announce to " );
143 dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
144 work->work_group );
147 send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
148 global_myname, 0x0, work->dmb_name.name, 0x0,
149 work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
153 /****************************************************************************
154 As a local master browser, do a sync with a domain master browser.
155 **************************************************************************/
157 static void sync_with_dmb(struct work_record *work)
159 if( DEBUGLVL( 2 ) )
161 dbgtext( "sync_with_dmb:\n" );
162 dbgtext( "Initiating sync with domain master browser " );
163 dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
164 dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
165 dbgtext( "for workgroup %s\n", work->work_group );
168 sync_browse_lists(work, work->dmb_name.name, work->dmb_name.name_type,
169 work->dmb_addr, False, True);
172 /****************************************************************************
173 Function called when a node status query to a domain master browser IP succeeds.
174 ****************************************************************************/
176 static void domain_master_node_status_success(struct subnet_record *subrec,
177 struct userdata_struct *userdata,
178 struct res_rec *answers,
179 struct in_addr from_ip)
181 struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
183 if( work == NULL )
185 if( DEBUGLVL( 0 ) )
187 dbgtext( "domain_master_node_status_success:\n" );
188 dbgtext( "Unable to find workgroup " );
189 dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
191 return;
194 if( DEBUGLVL( 3 ) )
196 dbgtext( "domain_master_node_status_success:\n" );
197 dbgtext( "Success in node status for workgroup " );
198 dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
201 /* Go through the list of names found at answers->rdata and look for
202 the first SERVER<0x20> name. */
204 if(answers->rdata != NULL)
206 char *p = answers->rdata;
207 int numnames = CVAL(p, 0);
209 p += 1;
211 while (numnames--)
213 char qname[17];
214 uint16 nb_flags;
215 int name_type;
217 StrnCpy(qname,p,15);
218 name_type = CVAL(p,15);
219 nb_flags = get_nb_flags(&p[16]);
220 trim_string(qname,NULL," ");
222 p += 18;
224 if(!(nb_flags & NB_GROUP) && (name_type == 0x20))
226 struct nmb_name nmbname;
228 make_nmb_name(&nmbname, qname, name_type);
230 /* Copy the dmb name and IP address
231 into the workgroup struct. */
233 work->dmb_name = nmbname;
234 putip((char *)&work->dmb_addr, &from_ip);
236 /* Do the local master browser announcement to the domain
237 master browser name and IP. */
238 announce_local_master_browser_to_domain_master_browser( work );
240 /* Now synchronise lists with the domain master browser. */
241 sync_with_dmb(work);
242 break;
246 else
247 if( DEBUGLVL( 0 ) )
249 dbgtext( "domain_master_node_status_success:\n" );
250 dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
251 dbgtext( "%s.\n", inet_ntoa(from_ip) );
255 /****************************************************************************
256 Function called when a node status query to a domain master browser IP fails.
257 ****************************************************************************/
259 static void domain_master_node_status_fail(struct subnet_record *subrec,
260 struct response_record *rrec)
262 struct userdata_struct *userdata = rrec->userdata;
264 if( DEBUGLVL( 0 ) )
266 dbgtext( "domain_master_node_status_fail:\n" );
267 dbgtext( "Doing a node status request to the domain master browser\n" );
268 dbgtext( "for workgroup %s ", userdata->data );
269 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
270 dbgtext( "Cannot sync browser lists.\n" );
274 /****************************************************************************
275 Function called when a query for a WORKGROUP<1b> name succeeds.
276 ****************************************************************************/
278 static void find_domain_master_name_query_success(struct subnet_record *subrec,
279 struct userdata_struct *userdata_in,
280 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
283 * Unfortunately, finding the IP address of the Domain Master Browser,
284 * as we have here, is not enough. We need to now do a sync to the
285 * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
286 * respond to the SMBSERVER name. To get this name from IP
287 * address we do a Node status request, and look for the first
288 * NAME<0x20> in the response, and take that as the server name.
289 * We also keep a cache of the Domain Master Browser name for this
290 * workgroup in the Workgroup struct, so that if the same IP addess
291 * is returned every time, we don't need to do the node status
292 * request.
295 struct work_record *work;
296 struct nmb_name nmbname;
297 struct userdata_struct *userdata;
298 int size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
300 if( !(work = find_workgroup_on_subnet(subrec, q_name->name)) )
302 if( DEBUGLVL( 0 ) )
304 dbgtext( "find_domain_master_name_query_success:\n" );
305 dbgtext( "Failed to find workgroup %s\n", q_name->name );
307 return;
310 /* First check if we already have a dmb for this workgroup. */
312 if(!ip_equal(work->dmb_addr, ipzero) && ip_equal(work->dmb_addr, answer_ip))
314 /* Do the local master browser announcement to the domain
315 master browser name and IP. */
316 announce_local_master_browser_to_domain_master_browser( work );
318 /* Now synchronise lists with the domain master browser. */
319 sync_with_dmb(work);
320 return;
322 else
323 putip((char *)&work->dmb_addr, &ipzero);
325 /* Now initiate the node status request. */
326 make_nmb_name(&nmbname,"*",0x0);
328 /* Put the workgroup name into the userdata so we know
329 what workgroup we're talking to when the reply comes
330 back. */
332 /* Setup the userdata_struct - this is copied so we can use
333 a stack variable for this. */
334 if((userdata = (struct userdata_struct *)malloc(size)) == NULL)
336 DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
337 return;
340 userdata->copy_fn = NULL;
341 userdata->free_fn = NULL;
342 userdata->userdata_len = strlen(work->work_group)+1;
343 pstrcpy(userdata->data, work->work_group);
345 node_status( subrec, &nmbname, answer_ip,
346 domain_master_node_status_success,
347 domain_master_node_status_fail,
348 userdata);
350 zero_free(userdata, size);
353 /****************************************************************************
354 Function called when a query for a WORKGROUP<1b> name fails.
355 ****************************************************************************/
356 static void find_domain_master_name_query_fail(struct subnet_record *subrec,
357 struct response_record *rrec,
358 struct nmb_name *question_name, int fail_code)
360 if( DEBUGLVL( 0 ) )
362 dbgtext( "find_domain_master_name_query_fail:\n" );
363 dbgtext( "Unable to find the Domain Master Browser name " );
364 dbgtext( "%s for the workgroup %s.\n",
365 nmb_namestr(question_name), question_name->name );
366 dbgtext( "Unable to sync browse lists in this workgroup.\n" );
370 /****************************************************************************
371 As a local master browser for a workgroup find the domain master browser
372 name, announce ourselves as local master browser to it and then pull the
373 full domain browse lists from it onto the given subnet.
374 **************************************************************************/
376 void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
377 struct work_record *work)
379 struct nmb_name nmbname;
381 /* Only do this if we are using a WINS server. */
382 if(we_are_a_wins_client() == False)
384 if( DEBUGLVL( 10 ) )
386 dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
387 dbgtext( "Ignoring, as we are not a WINS client.\n" );
389 return;
392 make_nmb_name(&nmbname,work->work_group,0x1b);
394 /* First, query for the WORKGROUP<1b> name from the WINS server. */
395 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
396 find_domain_master_name_query_success,
397 find_domain_master_name_query_fail,
398 NULL);
402 /****************************************************************************
403 Function called when a node status query to a domain master browser IP succeeds.
404 This function is only called on query to a Samba 1.9.18 or above WINS server.
406 Note that adding the workgroup name is enough for this workgroup to be
407 browsable by clients, as clients query the WINS server or broadcast
408 nets for the WORKGROUP<1b> name when they want to browse a workgroup
409 they are not in. We do not need to do a sync with this Domain Master
410 Browser in order for our browse clients to see machines in this workgroup.
411 JRA.
412 ****************************************************************************/
414 static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
415 struct userdata_struct *userdata,
416 struct res_rec *answers,
417 struct in_addr from_ip)
419 struct work_record *work;
420 fstring server_name;
422 server_name[0] = 0;
424 if( DEBUGLVL( 3 ) )
426 dbgtext( "get_domain_master_name_node_status_success:\n" );
427 dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
431 * Go through the list of names found at answers->rdata and look for
432 * the first WORKGROUP<0x1b> name.
435 if(answers->rdata != NULL)
437 char *p = answers->rdata;
438 int numnames = CVAL(p, 0);
440 p += 1;
442 while (numnames--)
444 char qname[17];
445 uint16 nb_flags;
446 int name_type;
448 StrnCpy(qname,p,15);
449 name_type = CVAL(p,15);
450 nb_flags = get_nb_flags(&p[16]);
451 trim_string(qname,NULL," ");
453 p += 18;
455 if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
456 server_name[0] == 0) {
457 /* this is almost certainly the server netbios name */
458 fstrcpy(server_name, qname);
459 continue;
462 if(!(nb_flags & NB_GROUP) && (name_type == 0x1b))
464 if( DEBUGLVL( 5 ) )
466 dbgtext( "get_domain_master_name_node_status_success:\n" );
467 dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
468 dbgtext( "is a domain master browser for workgroup " );
469 dbgtext( "%s. Adding this name.\n", qname );
473 * If we don't already know about this workgroup, add it
474 * to the workgroup list on the unicast_subnet.
476 if((work = find_workgroup_on_subnet( subrec, qname)) == NULL)
478 struct nmb_name nmbname;
480 * Add it - with an hour in the cache.
482 if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
483 return;
485 /* remember who the master is */
486 fstrcpy(work->local_master_browser_name, server_name);
487 make_nmb_name(&nmbname, server_name, 0x20);
488 work->dmb_name = nmbname;
489 work->dmb_addr = from_ip;
491 break;
495 else
496 if( DEBUGLVL( 0 ) )
498 dbgtext( "get_domain_master_name_node_status_success:\n" );
499 dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
500 dbgtext( "%s.\n", inet_ntoa(from_ip) );
504 /****************************************************************************
505 Function called when a node status query to a domain master browser IP fails.
506 ****************************************************************************/
508 static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
509 struct response_record *rrec)
511 if( DEBUGLVL( 0 ) )
513 dbgtext( "get_domain_master_name_node_status_fail:\n" );
514 dbgtext( "Doing a node status request to the domain master browser " );
515 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
516 dbgtext( "Cannot get workgroup name.\n" );
520 /****************************************************************************
521 Function called when a query for *<1b> name succeeds.
522 ****************************************************************************/
524 static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
525 struct userdata_struct *userdata_in,
526 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
529 * We now have a list of all the domain master browsers for all workgroups
530 * that have registered with the WINS server. Now do a node status request
531 * to each one and look for the first 1b name in the reply. This will be
532 * the workgroup name that we will add to the unicast subnet as a 'non-local'
533 * workgroup.
536 struct nmb_name nmbname;
537 struct in_addr send_ip;
538 int i;
540 if( DEBUGLVL( 5 ) )
542 dbgtext( "find_all_domain_master_names_query_succes:\n" );
543 dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
544 dbgtext( "IP addresses for Domain Master Browsers.\n" );
547 for(i = 0; i < rrec->rdlength / 6; i++)
549 /* Initiate the node status requests. */
550 make_nmb_name(&nmbname, "*", 0);
552 putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
555 * Don't send node status requests to ourself.
558 if(ismyip( send_ip ))
560 if( DEBUGLVL( 5 ) )
562 dbgtext( "find_all_domain_master_names_query_succes:\n" );
563 dbgtext( "Not sending node status to our own IP " );
564 dbgtext( "%s.\n", inet_ntoa(send_ip) );
566 continue;
569 if( DEBUGLVL( 5 ) )
571 dbgtext( "find_all_domain_master_names_query_success:\n" );
572 dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
575 node_status( subrec, &nmbname, send_ip,
576 get_domain_master_name_node_status_success,
577 get_domain_master_name_node_status_fail,
578 NULL);
582 /****************************************************************************
583 Function called when a query for *<1b> name fails.
584 ****************************************************************************/
585 static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
586 struct response_record *rrec,
587 struct nmb_name *question_name, int fail_code)
589 if( DEBUGLVL( 10 ) )
591 dbgtext( "find_domain_master_name_query_fail:\n" );
592 dbgtext( "WINS server did not reply to a query for name " );
593 dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
594 dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
598 /****************************************************************************
599 If we are a domain master browser on the unicast subnet, do a query to the
600 WINS server for the *<1b> name. This will only work to a Samba WINS server,
601 so ignore it if we fail. If we succeed, contact each of the IP addresses in
602 turn and do a node status request to them. If this succeeds then look for a
603 <1b> name in the reply - this is the workgroup name. Add this to the unicast
604 subnet. This is expensive, so we only do this every 15 minutes.
605 **************************************************************************/
606 void collect_all_workgroup_names_from_wins_server(time_t t)
608 static time_t lastrun = 0;
609 struct work_record *work;
610 struct nmb_name nmbname;
612 /* Only do this if we are using a WINS server. */
613 if(we_are_a_wins_client() == False)
614 return;
616 /* Check to see if we are a domain master browser on the unicast subnet. */
617 if((work = find_workgroup_on_subnet( unicast_subnet, global_myworkgroup)) == NULL)
619 if( DEBUGLVL( 0 ) )
621 dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
622 dbgtext( "Cannot find my workgroup %s ", global_myworkgroup );
623 dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
625 return;
628 if(!AM_DOMAIN_MASTER_BROWSER(work))
629 return;
631 if ((lastrun != 0) && (t < lastrun + (15 * 60)))
632 return;
634 lastrun = t;
636 make_nmb_name(&nmbname,"*",0x1b);
638 /* First, query for the *<1b> name from the WINS server. */
639 query_name(unicast_subnet, nmbname.name, nmbname.name_type,
640 find_all_domain_master_names_query_success,
641 find_all_domain_master_names_query_fail,
642 NULL);
646 /****************************************************************************
647 If we are a domain master browser on the unicast subnet, do a regular sync
648 with all other DMBs that we know of on that subnet.
650 To prevent exponential network traffic with large numbers of workgroups
651 we use a randomised system where sync probability is inversely proportional
652 to the number of known workgroups
653 **************************************************************************/
654 void sync_all_dmbs(time_t t)
656 static time_t lastrun = 0;
657 struct work_record *work;
658 int count=0;
660 /* Only do this if we are using a WINS server. */
661 if(we_are_a_wins_client() == False)
662 return;
664 /* Check to see if we are a domain master browser on the
665 unicast subnet. */
666 work = find_workgroup_on_subnet(unicast_subnet, global_myworkgroup);
667 if (!work) return;
669 if (!AM_DOMAIN_MASTER_BROWSER(work))
670 return;
672 if ((lastrun != 0) && (t < lastrun + (5 * 60)))
673 return;
675 /* count how many syncs we might need to do */
676 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
677 if (strcmp(global_myworkgroup, work->work_group)) {
678 count++;
682 /* sync with a probability of 1/count */
683 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
684 if (strcmp(global_myworkgroup, work->work_group)) {
685 if (((unsigned)sys_random()) % count != 0) continue;
687 lastrun = t;
689 if (!work->dmb_name.name[0]) {
690 /* we don't know the DMB - assume it is
691 the same as the unicast local master */
692 make_nmb_name(&work->dmb_name,
693 work->local_master_browser_name, 0x20);
696 DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
697 work->dmb_name.name,
698 inet_ntoa(work->dmb_addr)));
699 sync_browse_lists(work,
700 work->dmb_name.name,
701 work->dmb_name.name_type,
702 work->dmb_addr, False, False);