4a6f9f2d47d694a1d63b8f6d7a56d1622d154567
[samba.git] / source3 / nmbd / nmbd_browsesync.c
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 3 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, see <http://www.gnu.org/licenses/>.
20    
21 */
22
23 #include "includes.h"
24 #include "nmbd/nmbd.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         char outbuf[1024];
103         unstring myname;
104         unstring dmb_name;
105         char *p;
106
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" );
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_ascii(p, myname, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE);
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_v4(work->dmb_addr) && ip_equal_v4(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_v4(&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         strlcpy(userdata->data, work->work_group, size - sizeof(*userdata));
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_v4( 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         /* leave if we don't have to do any syncs */
649         if (count == 0) {
650                 return;
651         }
652
653         /* sync with a probability of 1/count */
654         for (work=unicast_subnet->workgrouplist; work; work = work->next) {
655                 if (strcmp(lp_workgroup(), work->work_group)) {
656                         unstring dmb_name;
657
658                         if (((unsigned)sys_random()) % count != 0)
659                                 continue;
660
661                         lastrun = t;
662
663                         if (!work->dmb_name.name[0]) {
664                                 /* we don't know the DMB - assume it is
665                                    the same as the unicast local master */
666                                 make_nmb_name(&work->dmb_name, 
667                                               work->local_master_browser_name,
668                                               0x20);
669                         }
670
671                         pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
672
673                         DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
674                                  dmb_name, inet_ntoa(work->dmb_addr)));
675
676                         sync_browse_lists(work, 
677                                           dmb_name,
678                                           work->dmb_name.name_type, 
679                                           work->dmb_addr, False, False);
680                 }
681         }
682 }