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 2 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, write to the Free Software
20
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
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(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, global_myname());
125
/* The call below does CH_UNIX -> CH_DOS conversion. JRA */
126
push_pstring_base(p, myname, outbuf);
128
p = skip_string(outbuf,sizeof(outbuf),p);
130
if( DEBUGLVL( 4 ) ) {
131
dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
132
dbgtext( "Sending local master announce to " );
133
dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
137
/* Target name for send_mailslot must be in UNIX charset. */
138
pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
139
send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
140
global_myname(), 0x0, dmb_name, 0x0,
141
work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
144
/****************************************************************************
145
As a local master browser, do a sync with a domain master browser.
146
**************************************************************************/
148
static void sync_with_dmb(struct work_record *work)
152
if( DEBUGLVL( 2 ) ) {
153
dbgtext( "sync_with_dmb:\n" );
154
dbgtext( "Initiating sync with domain master browser " );
155
dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
156
dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
157
dbgtext( "for workgroup %s\n", work->work_group );
160
pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
161
sync_browse_lists(work, dmb_name, work->dmb_name.name_type,
162
work->dmb_addr, False, True);
165
/****************************************************************************
166
Function called when a node status query to a domain master browser IP succeeds.
167
****************************************************************************/
169
static void domain_master_node_status_success(struct subnet_record *subrec,
170
struct userdata_struct *userdata,
171
struct res_rec *answers,
172
struct in_addr from_ip)
174
struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
177
if( DEBUGLVL( 0 ) ) {
178
dbgtext( "domain_master_node_status_success:\n" );
179
dbgtext( "Unable to find workgroup " );
180
dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
185
if( DEBUGLVL( 3 ) ) {
186
dbgtext( "domain_master_node_status_success:\n" );
187
dbgtext( "Success in node status for workgroup " );
188
dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
191
/* Go through the list of names found at answers->rdata and look for
192
the first SERVER<0x20> name. */
194
if(answers->rdata != NULL) {
195
char *p = answers->rdata;
196
int numnames = CVAL(p, 0);
205
pull_ascii_nstring(qname, sizeof(qname), p);
206
name_type = CVAL(p,15);
207
nb_flags = get_nb_flags(&p[16]);
208
trim_char(qname,'\0',' ');
212
if(!(nb_flags & NB_GROUP) && (name_type == 0x20)) {
213
struct nmb_name nmbname;
215
make_nmb_name(&nmbname, qname, name_type);
217
/* Copy the dmb name and IP address
218
into the workgroup struct. */
220
work->dmb_name = nmbname;
221
putip((char *)&work->dmb_addr, &from_ip);
223
/* Do the local master browser announcement to the domain
224
master browser name and IP. */
225
announce_local_master_browser_to_domain_master_browser( work );
227
/* Now synchronise lists with the domain master browser. */
232
} else if( DEBUGLVL( 0 ) ) {
233
dbgtext( "domain_master_node_status_success:\n" );
234
dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
235
dbgtext( "%s.\n", inet_ntoa(from_ip) );
239
/****************************************************************************
240
Function called when a node status query to a domain master browser IP fails.
241
****************************************************************************/
243
static void domain_master_node_status_fail(struct subnet_record *subrec,
244
struct response_record *rrec)
246
struct userdata_struct *userdata = rrec->userdata;
248
if( DEBUGLVL( 0 ) ) {
249
dbgtext( "domain_master_node_status_fail:\n" );
250
dbgtext( "Doing a node status request to the domain master browser\n" );
251
dbgtext( "for workgroup %s ", userdata ? userdata->data : "NULL" );
252
dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
253
dbgtext( "Cannot sync browser lists.\n" );
257
/****************************************************************************
258
Function called when a query for a WORKGROUP<1b> name succeeds.
259
****************************************************************************/
261
static void find_domain_master_name_query_success(struct subnet_record *subrec,
262
struct userdata_struct *userdata_in,
263
struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
266
* Unfortunately, finding the IP address of the Domain Master Browser,
267
* as we have here, is not enough. We need to now do a sync to the
268
* SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
269
* respond to the SMBSERVER name. To get this name from IP
270
* address we do a Node status request, and look for the first
271
* NAME<0x20> in the response, and take that as the server name.
272
* We also keep a cache of the Domain Master Browser name for this
273
* workgroup in the Workgroup struct, so that if the same IP addess
274
* is returned every time, we don't need to do the node status
278
struct work_record *work;
279
struct nmb_name nmbname;
280
struct userdata_struct *userdata;
281
size_t size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
284
pull_ascii_nstring(qname, sizeof(qname), q_name->name);
285
if( !(work = find_workgroup_on_subnet(subrec, qname)) ) {
286
if( DEBUGLVL( 0 ) ) {
287
dbgtext( "find_domain_master_name_query_success:\n" );
288
dbgtext( "Failed to find workgroup %s\n", qname);
293
/* First check if we already have a dmb for this workgroup. */
295
if(!is_zero_ip(work->dmb_addr) && ip_equal(work->dmb_addr, answer_ip)) {
296
/* Do the local master browser announcement to the domain
297
master browser name and IP. */
298
announce_local_master_browser_to_domain_master_browser( work );
300
/* Now synchronise lists with the domain master browser. */
304
zero_ip(&work->dmb_addr);
307
/* Now initiate the node status request. */
309
/* We used to use the name "*",0x0 here, but some Windows
310
* servers don't answer that name. However we *know* they
311
* have the name workgroup#1b (as we just looked it up).
312
* So do the node status request on this name instead.
313
* Found at LBL labs. JRA.
316
make_nmb_name(&nmbname,work->work_group,0x1b);
318
/* Put the workgroup name into the userdata so we know
319
what workgroup we're talking to when the reply comes
322
/* Setup the userdata_struct - this is copied so we can use
323
a stack variable for this. */
325
if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {
326
DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
330
userdata->copy_fn = NULL;
331
userdata->free_fn = NULL;
332
userdata->userdata_len = strlen(work->work_group)+1;
333
overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
335
node_status( subrec, &nmbname, answer_ip,
336
domain_master_node_status_success,
337
domain_master_node_status_fail,
340
zero_free(userdata, size);
343
/****************************************************************************
344
Function called when a query for a WORKGROUP<1b> name fails.
345
****************************************************************************/
347
static void find_domain_master_name_query_fail(struct subnet_record *subrec,
348
struct response_record *rrec,
349
struct nmb_name *question_name, int fail_code)
351
if( DEBUGLVL( 0 ) ) {
352
dbgtext( "find_domain_master_name_query_fail:\n" );
353
dbgtext( "Unable to find the Domain Master Browser name " );
354
dbgtext( "%s for the workgroup %s.\n",
355
nmb_namestr(question_name), question_name->name );
356
dbgtext( "Unable to sync browse lists in this workgroup.\n" );
360
/****************************************************************************
361
As a local master browser for a workgroup find the domain master browser
362
name, announce ourselves as local master browser to it and then pull the
363
full domain browse lists from it onto the given subnet.
364
**************************************************************************/
366
void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
367
struct work_record *work)
369
/* Only do this if we are using a WINS server. */
370
if(we_are_a_wins_client() == False) {
371
if( DEBUGLVL( 10 ) ) {
372
dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
373
dbgtext( "Ignoring, as we are not a WINS client.\n" );
378
/* First, query for the WORKGROUP<1b> name from the WINS server. */
379
query_name(unicast_subnet, work->work_group, 0x1b,
380
find_domain_master_name_query_success,
381
find_domain_master_name_query_fail,
385
/****************************************************************************
386
Function called when a node status query to a domain master browser IP succeeds.
387
This function is only called on query to a Samba 1.9.18 or above WINS server.
389
Note that adding the workgroup name is enough for this workgroup to be
390
browsable by clients, as clients query the WINS server or broadcast
391
nets for the WORKGROUP<1b> name when they want to browse a workgroup
392
they are not in. We do not need to do a sync with this Domain Master
393
Browser in order for our browse clients to see machines in this workgroup.
395
****************************************************************************/
397
static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
398
struct userdata_struct *userdata,
399
struct res_rec *answers,
400
struct in_addr from_ip)
402
struct work_record *work;
403
unstring server_name;
407
if( DEBUGLVL( 3 ) ) {
408
dbgtext( "get_domain_master_name_node_status_success:\n" );
409
dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
413
* Go through the list of names found at answers->rdata and look for
414
* the first WORKGROUP<0x1b> name.
417
if(answers->rdata != NULL) {
418
char *p = answers->rdata;
419
int numnames = CVAL(p, 0);
428
pull_ascii_nstring(qname, sizeof(qname), p);
429
name_type = CVAL(p,15);
430
nb_flags = get_nb_flags(&p[16]);
431
trim_char(qname,'\0',' ');
435
if(!(nb_flags & NB_GROUP) && (name_type == 0x00) &&
436
server_name[0] == 0) {
437
/* this is almost certainly the server netbios name */
438
unstrcpy(server_name, qname);
442
if(!(nb_flags & NB_GROUP) && (name_type == 0x1b)) {
443
if( DEBUGLVL( 5 ) ) {
444
dbgtext( "get_domain_master_name_node_status_success:\n" );
445
dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
446
dbgtext( "is a domain master browser for workgroup " );
447
dbgtext( "%s. Adding this name.\n", qname );
451
* If we don't already know about this workgroup, add it
452
* to the workgroup list on the unicast_subnet.
455
if((work = find_workgroup_on_subnet( subrec, qname)) == NULL) {
456
struct nmb_name nmbname;
458
* Add it - with an hour in the cache.
460
if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
463
/* remember who the master is */
464
unstrcpy(work->local_master_browser_name, server_name);
465
make_nmb_name(&nmbname, server_name, 0x20);
466
work->dmb_name = nmbname;
467
work->dmb_addr = from_ip;
472
} else if( DEBUGLVL( 0 ) ) {
473
dbgtext( "get_domain_master_name_node_status_success:\n" );
474
dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
475
dbgtext( "%s.\n", inet_ntoa(from_ip) );
479
/****************************************************************************
480
Function called when a node status query to a domain master browser IP fails.
481
****************************************************************************/
483
static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
484
struct response_record *rrec)
486
if( DEBUGLVL( 0 ) ) {
487
dbgtext( "get_domain_master_name_node_status_fail:\n" );
488
dbgtext( "Doing a node status request to the domain master browser " );
489
dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
490
dbgtext( "Cannot get workgroup name.\n" );
494
/****************************************************************************
495
Function called when a query for *<1b> name succeeds.
496
****************************************************************************/
498
static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
499
struct userdata_struct *userdata_in,
500
struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
503
* We now have a list of all the domain master browsers for all workgroups
504
* that have registered with the WINS server. Now do a node status request
505
* to each one and look for the first 1b name in the reply. This will be
506
* the workgroup name that we will add to the unicast subnet as a 'non-local'
510
struct nmb_name nmbname;
511
struct in_addr send_ip;
514
if( DEBUGLVL( 5 ) ) {
515
dbgtext( "find_all_domain_master_names_query_succes:\n" );
516
dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
517
dbgtext( "IP addresses for Domain Master Browsers.\n" );
520
for(i = 0; i < rrec->rdlength / 6; i++) {
521
/* Initiate the node status requests. */
522
make_nmb_name(&nmbname, "*", 0);
524
putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
527
* Don't send node status requests to ourself.
530
if(ismyip( send_ip )) {
531
if( DEBUGLVL( 5 ) ) {
532
dbgtext( "find_all_domain_master_names_query_succes:\n" );
533
dbgtext( "Not sending node status to our own IP " );
534
dbgtext( "%s.\n", inet_ntoa(send_ip) );
539
if( DEBUGLVL( 5 ) ) {
540
dbgtext( "find_all_domain_master_names_query_success:\n" );
541
dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
544
node_status( subrec, &nmbname, send_ip,
545
get_domain_master_name_node_status_success,
546
get_domain_master_name_node_status_fail,
551
/****************************************************************************
552
Function called when a query for *<1b> name fails.
553
****************************************************************************/
554
static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
555
struct response_record *rrec,
556
struct nmb_name *question_name, int fail_code)
558
if( DEBUGLVL( 10 ) ) {
559
dbgtext( "find_domain_master_name_query_fail:\n" );
560
dbgtext( "WINS server did not reply to a query for name " );
561
dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
562
dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
566
/****************************************************************************
567
If we are a domain master browser on the unicast subnet, do a query to the
568
WINS server for the *<1b> name. This will only work to a Samba WINS server,
569
so ignore it if we fail. If we succeed, contact each of the IP addresses in
570
turn and do a node status request to them. If this succeeds then look for a
571
<1b> name in the reply - this is the workgroup name. Add this to the unicast
572
subnet. This is expensive, so we only do this every 15 minutes.
573
**************************************************************************/
575
void collect_all_workgroup_names_from_wins_server(time_t t)
577
static time_t lastrun = 0;
578
struct work_record *work;
580
/* Only do this if we are using a WINS server. */
581
if(we_are_a_wins_client() == False)
584
/* Check to see if we are a domain master browser on the unicast subnet. */
585
if((work = find_workgroup_on_subnet( unicast_subnet, lp_workgroup())) == NULL) {
586
if( DEBUGLVL( 0 ) ) {
587
dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
588
dbgtext( "Cannot find my workgroup %s ", lp_workgroup() );
589
dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
594
if(!AM_DOMAIN_MASTER_BROWSER(work))
597
if ((lastrun != 0) && (t < lastrun + (15 * 60)))
602
/* First, query for the *<1b> name from the WINS server. */
603
query_name(unicast_subnet, "*", 0x1b,
604
find_all_domain_master_names_query_success,
605
find_all_domain_master_names_query_fail,
610
/****************************************************************************
611
If we are a domain master browser on the unicast subnet, do a regular sync
612
with all other DMBs that we know of on that subnet.
614
To prevent exponential network traffic with large numbers of workgroups
615
we use a randomised system where sync probability is inversely proportional
616
to the number of known workgroups
617
**************************************************************************/
619
void sync_all_dmbs(time_t t)
621
static time_t lastrun = 0;
622
struct work_record *work;
625
/* Only do this if we are using a WINS server. */
626
if(we_are_a_wins_client() == False)
629
/* Check to see if we are a domain master browser on the
631
work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup());
635
if (!AM_DOMAIN_MASTER_BROWSER(work))
638
if ((lastrun != 0) && (t < lastrun + (5 * 60)))
641
/* count how many syncs we might need to do */
642
for (work=unicast_subnet->workgrouplist; work; work = work->next) {
643
if (strcmp(lp_workgroup(), work->work_group)) {
648
/* sync with a probability of 1/count */
649
for (work=unicast_subnet->workgrouplist; work; work = work->next) {
650
if (strcmp(lp_workgroup(), work->work_group)) {
653
if (((unsigned)sys_random()) % count != 0)
658
if (!work->dmb_name.name[0]) {
659
/* we don't know the DMB - assume it is
660
the same as the unicast local master */
661
make_nmb_name(&work->dmb_name,
662
work->local_master_browser_name,
666
pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
668
DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
669
dmb_name, inet_ntoa(work->dmb_addr)));
671
sync_browse_lists(work,
673
work->dmb_name.name_type,
674
work->dmb_addr, False, False);