s3:smbXsrv_tcon: add smbXsrv_tcon_global_traverse()
[Samba.git] / source3 / nmbd / nmbd_browsesync.c
blobb56baedf270dcd101cc751cf486409c7c0224a1f
1 /*
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-2003
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 3 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, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "nmbd/nmbd.h"
26 /* This is our local master browser list database. */
27 extern struct browse_cache_record *lmb_browserlist;
29 /****************************************************************************
30 As a domain master browser, do a sync with a local master browser.
31 **************************************************************************/
33 static void sync_with_lmb(struct browse_cache_record *browc)
35 struct work_record *work;
37 if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) ) {
38 if( DEBUGLVL( 0 ) ) {
39 dbgtext( "sync_with_lmb:\n" );
40 dbgtext( "Failed to get a workgroup for a local master browser " );
41 dbgtext( "cache entry workgroup " );
42 dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
44 return;
47 /* We should only be doing this if we are a domain master browser for
48 the given workgroup. Ensure this is so. */
50 if(!AM_DOMAIN_MASTER_BROWSER(work)) {
51 if( DEBUGLVL( 0 ) ) {
52 dbgtext( "sync_with_lmb:\n" );
53 dbgtext( "We are trying to sync with a local master browser " );
54 dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
55 dbgtext( "and we are not a domain master browser on this workgroup.\n" );
56 dbgtext( "Error!\n" );
58 return;
61 if( DEBUGLVL( 2 ) ) {
62 dbgtext( "sync_with_lmb:\n" );
63 dbgtext( "Initiating sync with local master browser " );
64 dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
65 dbgtext( "for workgroup %s\n", browc->work_group );
68 sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
70 browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
73 /****************************************************************************
74 Sync or expire any local master browsers.
75 **************************************************************************/
77 void dmb_expire_and_sync_browser_lists(time_t t)
79 static time_t last_run = 0;
80 struct browse_cache_record *browc;
82 /* Only do this every 20 seconds. */
83 if (t - last_run < 20)
84 return;
86 last_run = t;
88 expire_lmb_browsers(t);
90 for( browc = lmb_browserlist; browc; browc = browc->next ) {
91 if (browc->sync_time < t)
92 sync_with_lmb(browc);
96 /****************************************************************************
97 As a local master browser, send an announce packet to the domain master browser.
98 **************************************************************************/
100 static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
102 char outbuf[1024];
103 unstring myname;
104 unstring dmb_name;
105 char *p;
107 if(ismyip_v4(work->dmb_addr)) {
108 if( DEBUGLVL( 2 ) ) {
109 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
110 dbgtext( "We are both a domain and a local master browser for " );
111 dbgtext( "workgroup %s. ", work->work_group );
112 dbgtext( "Do not announce to ourselves.\n" );
114 return;
117 memset(outbuf,'\0',sizeof(outbuf));
118 p = outbuf;
119 SCVAL(p,0,ANN_MasterAnnouncement);
120 p++;
122 unstrcpy(myname, lp_netbios_name());
123 if (!strupper_m(myname)) {
124 DEBUG(2,("strupper_m %s failed\n", myname));
125 return;
127 myname[15]='\0';
128 /* The call below does CH_UNIX -> CH_DOS conversion. JRA */
129 push_ascii(p, myname, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE);
131 p = skip_string(outbuf,sizeof(outbuf),p);
133 if( DEBUGLVL( 4 ) ) {
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),
137 work->work_group );
140 /* Target name for send_mailslot must be in UNIX charset. */
141 pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
142 send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
143 lp_netbios_name(), 0x0, dmb_name, 0x0,
144 work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
147 /****************************************************************************
148 As a local master browser, do a sync with a domain master browser.
149 **************************************************************************/
151 static void sync_with_dmb(struct work_record *work)
153 unstring dmb_name;
155 if( DEBUGLVL( 2 ) ) {
156 dbgtext( "sync_with_dmb:\n" );
157 dbgtext( "Initiating sync with domain master browser " );
158 dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
159 dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
160 dbgtext( "for workgroup %s\n", work->work_group );
163 pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
164 sync_browse_lists(work, dmb_name, work->dmb_name.name_type,
165 work->dmb_addr, False, True);
168 /****************************************************************************
169 Function called when a node status query to a domain master browser IP succeeds.
170 ****************************************************************************/
172 static void domain_master_node_status_success(struct subnet_record *subrec,
173 struct userdata_struct *userdata,
174 struct res_rec *answers,
175 struct in_addr from_ip)
177 struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
179 if( work == NULL ) {
180 if( DEBUGLVL( 0 ) ) {
181 dbgtext( "domain_master_node_status_success:\n" );
182 dbgtext( "Unable to find workgroup " );
183 dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
185 return;
188 if( DEBUGLVL( 3 ) ) {
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) {
198 char *p = answers->rdata;
199 int numnames = CVAL(p, 0);
201 p += 1;
203 while (numnames--) {
204 unstring qname;
205 uint16 nb_flags;
206 int name_type;
208 pull_ascii_nstring(qname, sizeof(qname), p);
209 name_type = CVAL(p,15);
210 nb_flags = get_nb_flags(&p[16]);
211 trim_char(qname,'\0',' ');
213 p += 18;
215 if(!(nb_flags & NB_GROUP) && (name_type == 0x20)) {
216 struct nmb_name nmbname;
218 make_nmb_name(&nmbname, qname, name_type);
220 /* Copy the dmb name and IP address
221 into the workgroup struct. */
223 work->dmb_name = nmbname;
224 putip((char *)&work->dmb_addr, &from_ip);
226 /* Do the local master browser announcement to the domain
227 master browser name and IP. */
228 announce_local_master_browser_to_domain_master_browser( work );
230 /* Now synchronise lists with the domain master browser. */
231 sync_with_dmb(work);
232 break;
235 } else if( DEBUGLVL( 0 ) ) {
236 dbgtext( "domain_master_node_status_success:\n" );
237 dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
238 dbgtext( "%s.\n", inet_ntoa(from_ip) );
242 /****************************************************************************
243 Function called when a node status query to a domain master browser IP fails.
244 ****************************************************************************/
246 static void domain_master_node_status_fail(struct subnet_record *subrec,
247 struct response_record *rrec)
249 struct userdata_struct *userdata = rrec->userdata;
251 if( DEBUGLVL( 0 ) ) {
252 dbgtext( "domain_master_node_status_fail:\n" );
253 dbgtext( "Doing a node status request to the domain master browser\n" );
254 dbgtext( "for workgroup %s ", userdata ? userdata->data : "NULL" );
255 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
256 dbgtext( "Cannot sync browser lists.\n" );
260 /****************************************************************************
261 Function called when a query for a WORKGROUP<1b> name succeeds.
262 ****************************************************************************/
264 static void find_domain_master_name_query_success(struct subnet_record *subrec,
265 struct userdata_struct *userdata_in,
266 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
269 * Unfortunately, finding the IP address of the Domain Master Browser,
270 * as we have here, is not enough. We need to now do a sync to the
271 * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
272 * respond to the SMBSERVER name. To get this name from IP
273 * address we do a Node status request, and look for the first
274 * NAME<0x20> in the response, and take that as the server name.
275 * We also keep a cache of the Domain Master Browser name for this
276 * workgroup in the Workgroup struct, so that if the same IP addess
277 * is returned every time, we don't need to do the node status
278 * request.
281 struct work_record *work;
282 struct nmb_name nmbname;
283 struct userdata_struct *userdata;
284 size_t size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
285 unstring qname;
287 pull_ascii_nstring(qname, sizeof(qname), q_name->name);
288 if( !(work = find_workgroup_on_subnet(subrec, qname)) ) {
289 if( DEBUGLVL( 0 ) ) {
290 dbgtext( "find_domain_master_name_query_success:\n" );
291 dbgtext( "Failed to find workgroup %s\n", qname);
293 return;
296 /* First check if we already have a dmb for this workgroup. */
298 if(!is_zero_ip_v4(work->dmb_addr) && ip_equal_v4(work->dmb_addr, answer_ip)) {
299 /* Do the local master browser announcement to the domain
300 master browser name and IP. */
301 announce_local_master_browser_to_domain_master_browser( work );
303 /* Now synchronise lists with the domain master browser. */
304 sync_with_dmb(work);
305 return;
306 } else {
307 zero_ip_v4(&work->dmb_addr);
310 /* Now initiate the node status request. */
312 /* We used to use the name "*",0x0 here, but some Windows
313 * servers don't answer that name. However we *know* they
314 * have the name workgroup#1b (as we just looked it up).
315 * So do the node status request on this name instead.
316 * Found at LBL labs. JRA.
319 make_nmb_name(&nmbname,work->work_group,0x1b);
321 /* Put the workgroup name into the userdata so we know
322 what workgroup we're talking to when the reply comes
323 back. */
325 /* Setup the userdata_struct - this is copied so we can use
326 a stack variable for this. */
328 if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {
329 DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
330 return;
333 userdata->copy_fn = NULL;
334 userdata->free_fn = NULL;
335 userdata->userdata_len = strlen(work->work_group)+1;
336 strlcpy(userdata->data, work->work_group, size - sizeof(*userdata));
338 node_status( subrec, &nmbname, answer_ip,
339 domain_master_node_status_success,
340 domain_master_node_status_fail,
341 userdata);
343 zero_free(userdata, size);
346 /****************************************************************************
347 Function called when a query for a WORKGROUP<1b> name fails.
348 ****************************************************************************/
350 static void find_domain_master_name_query_fail(struct subnet_record *subrec,
351 struct response_record *rrec,
352 struct nmb_name *question_name, int fail_code)
354 if( DEBUGLVL( 0 ) ) {
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 /* Only do this if we are using a WINS server. */
373 if(we_are_a_wins_client() == False) {
374 if( DEBUGLVL( 10 ) ) {
375 dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
376 dbgtext( "Ignoring, as we are not a WINS client.\n" );
378 return;
381 /* First, query for the WORKGROUP<1b> name from the WINS server. */
382 query_name(unicast_subnet, work->work_group, 0x1b,
383 find_domain_master_name_query_success,
384 find_domain_master_name_query_fail,
385 NULL);
388 /****************************************************************************
389 Function called when a node status query to a domain master browser IP succeeds.
390 This function is only called on query to a Samba 1.9.18 or above WINS server.
392 Note that adding the workgroup name is enough for this workgroup to be
393 browsable by clients, as clients query the WINS server or broadcast
394 nets for the WORKGROUP<1b> name when they want to browse a workgroup
395 they are not in. We do not need to do a sync with this Domain Master
396 Browser in order for our browse clients to see machines in this workgroup.
397 JRA.
398 ****************************************************************************/
400 static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
401 struct userdata_struct *userdata,
402 struct res_rec *answers,
403 struct in_addr from_ip)
405 struct work_record *work;
406 unstring server_name;
408 server_name[0] = 0;
410 if( DEBUGLVL( 3 ) ) {
411 dbgtext( "get_domain_master_name_node_status_success:\n" );
412 dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
416 * Go through the list of names found at answers->rdata and look for
417 * the first WORKGROUP<0x1b> name.
420 if(answers->rdata != NULL) {
421 char *p = answers->rdata;
422 int numnames = CVAL(p, 0);
424 p += 1;
426 while (numnames--) {
427 unstring qname;
428 uint16 nb_flags;
429 int name_type;
431 pull_ascii_nstring(qname, sizeof(qname), p);
432 name_type = CVAL(p,15);
433 nb_flags = get_nb_flags(&p[16]);
434 trim_char(qname,'\0',' ');
436 p += 18;
438 if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
439 server_name[0] == 0) {
440 /* this is almost certainly the server netbios name */
441 strlcpy(server_name, qname, sizeof(server_name));
442 continue;
445 if(!(nb_flags & NB_GROUP) && (name_type == 0x1b)) {
446 if( DEBUGLVL( 5 ) ) {
447 dbgtext( "get_domain_master_name_node_status_success:\n" );
448 dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
449 dbgtext( "is a domain master browser for workgroup " );
450 dbgtext( "%s. Adding this name.\n", qname );
454 * If we don't already know about this workgroup, add it
455 * to the workgroup list on the unicast_subnet.
458 if((work = find_workgroup_on_subnet( subrec, qname)) == NULL) {
459 struct nmb_name nmbname;
461 * Add it - with an hour in the cache.
463 if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
464 return;
466 /* remember who the master is */
467 strlcpy(work->local_master_browser_name,
468 server_name,
469 sizeof(work->local_master_browser_name));
470 make_nmb_name(&nmbname, server_name, 0x20);
471 work->dmb_name = nmbname;
472 work->dmb_addr = from_ip;
474 break;
477 } else if( DEBUGLVL( 1 ) ) {
478 dbgtext( "get_domain_master_name_node_status_success:\n" );
479 dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
480 dbgtext( "%s.\n", inet_ntoa(from_ip) );
484 /****************************************************************************
485 Function called when a node status query to a domain master browser IP fails.
486 ****************************************************************************/
488 static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
489 struct response_record *rrec)
491 if( DEBUGLVL( 2 ) ) {
492 dbgtext( "get_domain_master_name_node_status_fail:\n" );
493 dbgtext( "Doing a node status request to the domain master browser " );
494 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
495 dbgtext( "Cannot get workgroup name.\n" );
499 /****************************************************************************
500 Function called when a query for *<1b> name succeeds.
501 ****************************************************************************/
503 static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
504 struct userdata_struct *userdata_in,
505 struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
508 * We now have a list of all the domain master browsers for all workgroups
509 * that have registered with the WINS server. Now do a node status request
510 * to each one and look for the first 1b name in the reply. This will be
511 * the workgroup name that we will add to the unicast subnet as a 'non-local'
512 * workgroup.
515 struct nmb_name nmbname;
516 struct in_addr send_ip;
517 int i;
519 if( DEBUGLVL( 5 ) ) {
520 dbgtext( "find_all_domain_master_names_query_succes:\n" );
521 dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
522 dbgtext( "IP addresses for Domain Master Browsers.\n" );
525 for(i = 0; i < rrec->rdlength / 6; i++) {
526 /* Initiate the node status requests. */
527 make_nmb_name(&nmbname, "*", 0);
529 putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
532 * Don't send node status requests to ourself.
535 if(ismyip_v4( send_ip )) {
536 if( DEBUGLVL( 5 ) ) {
537 dbgtext( "find_all_domain_master_names_query_succes:\n" );
538 dbgtext( "Not sending node status to our own IP " );
539 dbgtext( "%s.\n", inet_ntoa(send_ip) );
541 continue;
544 if( DEBUGLVL( 5 ) ) {
545 dbgtext( "find_all_domain_master_names_query_success:\n" );
546 dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
549 node_status( subrec, &nmbname, send_ip,
550 get_domain_master_name_node_status_success,
551 get_domain_master_name_node_status_fail,
552 NULL);
556 /****************************************************************************
557 Function called when a query for *<1b> name fails.
558 ****************************************************************************/
559 static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
560 struct response_record *rrec,
561 struct nmb_name *question_name, int fail_code)
563 if( DEBUGLVL( 10 ) ) {
564 dbgtext( "find_domain_master_name_query_fail:\n" );
565 dbgtext( "WINS server did not reply to a query for name " );
566 dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
567 dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
571 /****************************************************************************
572 If we are a domain master browser on the unicast subnet, do a query to the
573 WINS server for the *<1b> name. This will only work to a Samba WINS server,
574 so ignore it if we fail. If we succeed, contact each of the IP addresses in
575 turn and do a node status request to them. If this succeeds then look for a
576 <1b> name in the reply - this is the workgroup name. Add this to the unicast
577 subnet. This is expensive, so we only do this every 15 minutes.
578 **************************************************************************/
580 void collect_all_workgroup_names_from_wins_server(time_t t)
582 static time_t lastrun = 0;
583 struct work_record *work;
585 /* Only do this if we are using a WINS server. */
586 if(we_are_a_wins_client() == False)
587 return;
589 /* Check to see if we are a domain master browser on the unicast subnet. */
590 if((work = find_workgroup_on_subnet( unicast_subnet, lp_workgroup())) == NULL) {
591 if( DEBUGLVL( 0 ) ) {
592 dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
593 dbgtext( "Cannot find my workgroup %s ", lp_workgroup() );
594 dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
596 return;
599 if(!AM_DOMAIN_MASTER_BROWSER(work))
600 return;
602 if ((lastrun != 0) && (t < lastrun + (15 * 60)))
603 return;
605 lastrun = t;
607 /* First, query for the *<1b> name from the WINS server. */
608 query_name(unicast_subnet, "*", 0x1b,
609 find_all_domain_master_names_query_success,
610 find_all_domain_master_names_query_fail,
611 NULL);
615 /****************************************************************************
616 If we are a domain master browser on the unicast subnet, do a regular sync
617 with all other DMBs that we know of on that subnet.
619 To prevent exponential network traffic with large numbers of workgroups
620 we use a randomised system where sync probability is inversely proportional
621 to the number of known workgroups
622 **************************************************************************/
624 void sync_all_dmbs(time_t t)
626 static time_t lastrun = 0;
627 struct work_record *work;
628 int count=0;
630 /* Only do this if we are using a WINS server. */
631 if(we_are_a_wins_client() == False)
632 return;
634 /* Check to see if we are a domain master browser on the
635 unicast subnet. */
636 work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup());
637 if (!work)
638 return;
640 if (!AM_DOMAIN_MASTER_BROWSER(work))
641 return;
643 if ((lastrun != 0) && (t < lastrun + (5 * 60)))
644 return;
646 /* count how many syncs we might need to do */
647 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
648 if (strcmp(lp_workgroup(), work->work_group)) {
649 count++;
653 /* leave if we don't have to do any syncs */
654 if (count == 0) {
655 return;
658 /* sync with a probability of 1/count */
659 for (work=unicast_subnet->workgrouplist; work; work = work->next) {
660 if (strcmp(lp_workgroup(), work->work_group)) {
661 unstring dmb_name;
663 if (((unsigned)sys_random()) % count != 0)
664 continue;
666 lastrun = t;
668 if (!work->dmb_name.name[0]) {
669 /* we don't know the DMB - assume it is
670 the same as the unicast local master */
671 make_nmb_name(&work->dmb_name,
672 work->local_master_browser_name,
673 0x20);
676 pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
678 DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
679 dmb_name, inet_ntoa(work->dmb_addr)));
681 sync_browse_lists(work,
682 dmb_name,
683 work->dmb_name.name_type,
684 work->dmb_addr, False, False);