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/>.
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
)) ) {
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
);
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
)) {
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" );
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)
88 expire_lmb_browsers(t
);
90 for( browc
= lmb_browserlist
; browc
; browc
= browc
->next
) {
91 if (browc
->sync_time
< t
)
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
)
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" );
117 memset(outbuf
,'\0',sizeof(outbuf
));
119 SCVAL(p
,0,ANN_MasterAnnouncement
);
122 unstrcpy(myname
, lp_netbios_name());
123 if (!strupper_m(myname
)) {
124 DEBUG(2,("strupper_m %s failed\n", myname
));
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
),
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
)
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
);
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
);
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);
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',' ');
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. */
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
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;
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
);
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. */
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
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"));
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
,
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" );
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
,
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.
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
;
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);
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',' ');
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
));
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)))
466 /* remember who the master is */
467 strlcpy(work
->local_master_browser_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
;
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'
515 struct nmb_name nmbname
;
516 struct in_addr send_ip
;
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
) );
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
,
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
)
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
);
599 if(!AM_DOMAIN_MASTER_BROWSER(work
))
602 if ((lastrun
!= 0) && (t
< lastrun
+ (15 * 60)))
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
,
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
;
630 /* Only do this if we are using a WINS server. */
631 if(we_are_a_wins_client() == False
)
634 /* Check to see if we are a domain master browser on the
636 work
= find_workgroup_on_subnet(unicast_subnet
, lp_workgroup());
640 if (!AM_DOMAIN_MASTER_BROWSER(work
))
643 if ((lastrun
!= 0) && (t
< lastrun
+ (5 * 60)))
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
)) {
653 /* leave if we don't have to do any syncs */
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
)) {
663 if (((unsigned)sys_random()) % count
!= 0)
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
,
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
,
683 work
->dmb_name
.name_type
,
684 work
->dmb_addr
, False
, False
);