~zulcss/samba/server-dailies-3.0.37

« back to all changes in this revision

Viewing changes to source/nmbd/nmbd_browsesync.c

  • Committer: Chuck Short
  • Date: 2010-09-28 20:24:01 UTC
  • Revision ID: zulcss@ubuntu.com-20100928202401-tgh438aoatxv3zp3
Initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 
7
   
 
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.
 
12
   
 
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.
 
17
   
 
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.
 
21
   
 
22
*/
 
23
 
 
24
#include "includes.h"
 
25
 
 
26
/* This is our local master browser list database. */
 
27
extern struct browse_cache_record *lmb_browserlist;
 
28
 
 
29
/****************************************************************************
 
30
As a domain master browser, do a sync with a local master browser.
 
31
**************************************************************************/
 
32
 
 
33
static void sync_with_lmb(struct browse_cache_record *browc)
 
34
{                     
 
35
        struct work_record *work;
 
36
 
 
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 );
 
43
                }
 
44
                return;
 
45
        }
 
46
 
 
47
        /* We should only be doing this if we are a domain master browser for
 
48
                the given workgroup. Ensure this is so. */
 
49
 
 
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" );
 
57
                }
 
58
                return;
 
59
        }
 
60
 
 
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 );
 
66
        }
 
67
 
 
68
        sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
 
69
 
 
70
        browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
 
71
}
 
72
 
 
73
/****************************************************************************
 
74
Sync or expire any local master browsers.
 
75
**************************************************************************/
 
76
 
 
77
void dmb_expire_and_sync_browser_lists(time_t t)
 
78
{
 
79
        static time_t last_run = 0;
 
80
        struct browse_cache_record *browc;
 
81
 
 
82
        /* Only do this every 20 seconds. */  
 
83
        if (t - last_run < 20) 
 
84
                return;
 
85
 
 
86
        last_run = t;
 
87
 
 
88
        expire_lmb_browsers(t);
 
89
 
 
90
        for( browc = lmb_browserlist; browc; browc = browc->next ) {
 
91
                if (browc->sync_time < t)
 
92
                        sync_with_lmb(browc);
 
93
        }
 
94
}
 
95
 
 
96
/****************************************************************************
 
97
As a local master browser, send an announce packet to the domain master browser.
 
98
**************************************************************************/
 
99
 
 
100
static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
 
101
{
 
102
        pstring outbuf;
 
103
        unstring myname;
 
104
        unstring dmb_name;
 
105
        char *p;
 
106
 
 
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" );
 
113
                }
 
114
                return;
 
115
        }
 
116
 
 
117
        memset(outbuf,'\0',sizeof(outbuf));
 
118
        p = outbuf;
 
119
        SCVAL(p,0,ANN_MasterAnnouncement);
 
120
        p++;
 
121
 
 
122
        unstrcpy(myname, global_myname());
 
123
        strupper_m(myname);
 
124
        myname[15]='\0';
 
125
        /* The call below does CH_UNIX -> CH_DOS conversion. JRA */
 
126
        push_pstring_base(p, myname, outbuf);
 
127
 
 
128
        p = skip_string(outbuf,sizeof(outbuf),p);
 
129
 
 
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),
 
134
                                        work->work_group );
 
135
        }
 
136
 
 
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);
 
142
}
 
143
 
 
144
/****************************************************************************
 
145
As a local master browser, do a sync with a domain master browser.
 
146
**************************************************************************/
 
147
 
 
148
static void sync_with_dmb(struct work_record *work)
 
149
{
 
150
        unstring dmb_name;
 
151
 
 
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 );
 
158
        }
 
159
 
 
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);
 
163
}
 
164
 
 
165
/****************************************************************************
 
166
  Function called when a node status query to a domain master browser IP succeeds.
 
167
****************************************************************************/
 
168
 
 
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)
 
173
{
 
174
        struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
 
175
 
 
176
        if( work == NULL ) {
 
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 );
 
181
                }
 
182
                return;
 
183
        }
 
184
 
 
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) );
 
189
        }
 
190
 
 
191
  /* Go through the list of names found at answers->rdata and look for
 
192
     the first SERVER<0x20> name. */
 
193
 
 
194
        if(answers->rdata != NULL) {
 
195
                char *p = answers->rdata;
 
196
                int numnames = CVAL(p, 0);
 
197
 
 
198
                p += 1;
 
199
 
 
200
                while (numnames--) {
 
201
                        unstring qname;
 
202
                        uint16 nb_flags;
 
203
                        int name_type;
 
204
 
 
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',' ');
 
209
 
 
210
                        p += 18;
 
211
 
 
212
                        if(!(nb_flags & NB_GROUP) && (name_type == 0x20)) {
 
213
                                struct nmb_name nmbname;
 
214
 
 
215
                                make_nmb_name(&nmbname, qname, name_type);
 
216
 
 
217
                                /* Copy the dmb name and IP address
 
218
                                        into the workgroup struct. */
 
219
 
 
220
                                work->dmb_name = nmbname;
 
221
                                putip((char *)&work->dmb_addr, &from_ip);
 
222
 
 
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 );
 
226
 
 
227
                                /* Now synchronise lists with the domain master browser. */
 
228
                                sync_with_dmb(work);
 
229
                                break;
 
230
                        }
 
231
                }
 
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) );
 
236
        }
 
237
}
 
238
 
 
239
/****************************************************************************
 
240
  Function called when a node status query to a domain master browser IP fails.
 
241
****************************************************************************/
 
242
 
 
243
static void domain_master_node_status_fail(struct subnet_record *subrec,
 
244
                       struct response_record *rrec)
 
245
{
 
246
        struct userdata_struct *userdata = rrec->userdata;
 
247
 
 
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" );
 
254
        }
 
255
}
 
256
 
 
257
/****************************************************************************
 
258
  Function called when a query for a WORKGROUP<1b> name succeeds.
 
259
****************************************************************************/
 
260
 
 
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)
 
264
{
 
265
        /* 
 
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
 
275
         * request.
 
276
         */
 
277
 
 
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;
 
282
        unstring qname;
 
283
 
 
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);
 
289
                }
 
290
        return;
 
291
  }
 
292
 
 
293
  /* First check if we already have a dmb for this workgroup. */
 
294
 
 
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 );
 
299
 
 
300
                /* Now synchronise lists with the domain master browser. */
 
301
                sync_with_dmb(work);
 
302
                return;
 
303
        } else {
 
304
                zero_ip(&work->dmb_addr);
 
305
        }
 
306
 
 
307
        /* Now initiate the node status request. */
 
308
 
 
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.
 
314
         */
 
315
 
 
316
        make_nmb_name(&nmbname,work->work_group,0x1b);
 
317
 
 
318
        /* Put the workgroup name into the userdata so we know
 
319
         what workgroup we're talking to when the reply comes
 
320
         back. */
 
321
 
 
322
        /* Setup the userdata_struct - this is copied so we can use
 
323
        a stack variable for this. */
 
324
 
 
325
        if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {
 
326
                DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
 
327
                return;
 
328
        }
 
329
 
 
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);
 
334
 
 
335
        node_status( subrec, &nmbname, answer_ip, 
 
336
                domain_master_node_status_success,
 
337
                domain_master_node_status_fail,
 
338
                userdata);
 
339
 
 
340
        zero_free(userdata, size);
 
341
}
 
342
 
 
343
/****************************************************************************
 
344
  Function called when a query for a WORKGROUP<1b> name fails.
 
345
  ****************************************************************************/
 
346
 
 
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)
 
350
{
 
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" );
 
357
        }
 
358
}
 
359
 
 
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
**************************************************************************/
 
365
 
 
366
void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
 
367
                                                   struct work_record *work)
 
368
{
 
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" );
 
374
                }
 
375
                return;
 
376
        }
 
377
 
 
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,
 
382
             NULL);
 
383
}
 
384
 
 
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.
 
388
 
 
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.
 
394
  JRA.
 
395
****************************************************************************/
 
396
 
 
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)
 
401
{
 
402
        struct work_record *work;
 
403
        unstring server_name;
 
404
 
 
405
        server_name[0] = 0;
 
406
 
 
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) );
 
410
        }
 
411
 
 
412
        /* 
 
413
         * Go through the list of names found at answers->rdata and look for
 
414
         * the first WORKGROUP<0x1b> name.
 
415
         */
 
416
 
 
417
        if(answers->rdata != NULL) {
 
418
                char *p = answers->rdata;
 
419
                int numnames = CVAL(p, 0);
 
420
 
 
421
                p += 1;
 
422
 
 
423
                while (numnames--) {
 
424
                        unstring qname;
 
425
                        uint16 nb_flags;
 
426
                        int name_type;
 
427
 
 
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',' ');
 
432
 
 
433
                        p += 18;
 
434
 
 
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);
 
439
                                continue;
 
440
                        }
 
441
 
 
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 );
 
448
                                }
 
449
 
 
450
                                /* 
 
451
                                 * If we don't already know about this workgroup, add it
 
452
                                 * to the workgroup list on the unicast_subnet.
 
453
                                 */
 
454
 
 
455
                                if((work = find_workgroup_on_subnet( subrec, qname)) == NULL) {
 
456
                                        struct nmb_name nmbname;
 
457
                                        /* 
 
458
                                         * Add it - with an hour in the cache.
 
459
                                         */
 
460
                                        if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
 
461
                                                return;
 
462
 
 
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;
 
468
                                }
 
469
                                break;
 
470
                        }
 
471
                }
 
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) );
 
476
        }
 
477
}
 
478
 
 
479
/****************************************************************************
 
480
  Function called when a node status query to a domain master browser IP fails.
 
481
****************************************************************************/
 
482
 
 
483
static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
 
484
                       struct response_record *rrec)
 
485
{
 
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" );
 
491
        }
 
492
}
 
493
 
 
494
/****************************************************************************
 
495
  Function called when a query for *<1b> name succeeds.
 
496
****************************************************************************/
 
497
 
 
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)
 
501
{
 
502
        /* 
 
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'
 
507
         * workgroup.
 
508
         */
 
509
 
 
510
        struct nmb_name nmbname;
 
511
        struct in_addr send_ip;
 
512
        int i;
 
513
 
 
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" );
 
518
        }
 
519
 
 
520
        for(i = 0; i < rrec->rdlength / 6; i++) {
 
521
                /* Initiate the node status requests. */
 
522
                make_nmb_name(&nmbname, "*", 0);
 
523
 
 
524
                putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
 
525
 
 
526
                /* 
 
527
                 * Don't send node status requests to ourself.
 
528
                 */
 
529
 
 
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) );
 
535
                        }
 
536
                        continue;
 
537
                }
 
538
 
 
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) );
 
542
                }
 
543
 
 
544
                node_status( subrec, &nmbname, send_ip, 
 
545
                                get_domain_master_name_node_status_success,
 
546
                                get_domain_master_name_node_status_fail,
 
547
                                NULL);
 
548
        }
 
549
}
 
550
 
 
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)
 
557
{
 
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" );
 
563
        }
 
564
}
 
565
 
 
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
**************************************************************************/
 
574
 
 
575
void collect_all_workgroup_names_from_wins_server(time_t t)
 
576
{
 
577
        static time_t lastrun = 0;
 
578
        struct work_record *work;
 
579
 
 
580
        /* Only do this if we are using a WINS server. */
 
581
        if(we_are_a_wins_client() == False)
 
582
                return;
 
583
 
 
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 );
 
590
                }
 
591
                return;
 
592
        }
 
593
 
 
594
        if(!AM_DOMAIN_MASTER_BROWSER(work))
 
595
                return;
 
596
 
 
597
        if ((lastrun != 0) && (t < lastrun + (15 * 60)))
 
598
                return;
 
599
     
 
600
        lastrun = t;
 
601
 
 
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,
 
606
                NULL);
 
607
 
608
 
 
609
 
 
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.
 
613
 
 
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
**************************************************************************/
 
618
 
 
619
void sync_all_dmbs(time_t t)
 
620
{
 
621
        static time_t lastrun = 0;
 
622
        struct work_record *work;
 
623
        int count=0;
 
624
 
 
625
        /* Only do this if we are using a WINS server. */
 
626
        if(we_are_a_wins_client() == False)
 
627
                return;
 
628
 
 
629
        /* Check to see if we are a domain master browser on the
 
630
           unicast subnet. */
 
631
        work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup());
 
632
        if (!work)
 
633
                return;
 
634
 
 
635
        if (!AM_DOMAIN_MASTER_BROWSER(work))
 
636
                return;
 
637
 
 
638
        if ((lastrun != 0) && (t < lastrun + (5 * 60)))
 
639
                return;
 
640
     
 
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)) {
 
644
                        count++;
 
645
                }
 
646
        }
 
647
 
 
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)) {
 
651
                        unstring dmb_name;
 
652
 
 
653
                        if (((unsigned)sys_random()) % count != 0)
 
654
                                continue;
 
655
 
 
656
                        lastrun = t;
 
657
 
 
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,
 
663
                                              0x20);
 
664
                        }
 
665
 
 
666
                        pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
 
667
 
 
668
                        DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
 
669
                                 dmb_name, inet_ntoa(work->dmb_addr)));
 
670
 
 
671
                        sync_browse_lists(work, 
 
672
                                          dmb_name,
 
673
                                          work->dmb_name.name_type, 
 
674
                                          work->dmb_addr, False, False);
 
675
                }
 
676
        }
 
677
}