b1517f89c9f27a6941e4cef43cc981fff8caee01
[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, lp_netbios_name());
123         if (!strupper_m(myname)) {
124                 DEBUG(2,("strupper_m %s failed\n", myname));
125                 return;
126         }
127         myname[15]='\0';
128         /* The call below does CH_UNIX -> CH_DOS conversion. JRA */
129         push_ascii(p, myname, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE);
130
131         p = skip_string(outbuf,sizeof(outbuf),p);
132
133         if( DEBUGLVL( 4 ) ) {
134                 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
135                 dbgtext( "Sending local master announce to " );
136                 dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
137                                         work->work_group );
138         }
139
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);
145 }
146
147 /****************************************************************************
148 As a local master browser, do a sync with a domain master browser.
149 **************************************************************************/
150
151 static void sync_with_dmb(struct work_record *work)
152 {
153         unstring dmb_name;
154
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 );
161         }
162
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);
166 }
167
168 /****************************************************************************
169   Function called when a node status query to a domain master browser IP succeeds.
170 ****************************************************************************/
171
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)
176 {
177         struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
178
179         if( work == NULL ) {
180                 if( DEBUGLVL( 0 ) ) {
181                         dbgtext( "domain_master_node_status_success:\n" );
182                         dbgtext( "Unable to find workgroup " );
183                         dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
184                 }
185                 return;
186         }
187
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) );
192         }
193
194   /* Go through the list of names found at answers->rdata and look for
195      the first SERVER<0x20> name. */
196
197         if (answers->rdlength > 0) {
198                 char *p = answers->rdata;
199                 int numnames = CVAL(p, 0);
200
201                 p += 1;
202
203                 while (numnames--) {
204                         unstring qname;
205                         uint16_t nb_flags;
206                         int name_type;
207
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',' ');
212
213                         p += 18;
214
215                         if(!(nb_flags & NB_GROUP) && (name_type == 0x20)) {
216                                 struct nmb_name nmbname;
217
218                                 make_nmb_name(&nmbname, qname, name_type);
219
220                                 /* Copy the dmb name and IP address
221                                         into the workgroup struct. */
222
223                                 work->dmb_name = nmbname;
224                                 putip((char *)&work->dmb_addr, &from_ip);
225
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 );
229
230                                 /* Now synchronise lists with the domain master browser. */
231                                 sync_with_dmb(work);
232                                 break;
233                         }
234                 }
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) );
239         }
240 }
241
242 /****************************************************************************
243   Function called when a node status query to a domain master browser IP fails.
244 ****************************************************************************/
245
246 static void domain_master_node_status_fail(struct subnet_record *subrec,
247                        struct response_record *rrec)
248 {
249         struct userdata_struct *userdata = rrec->userdata;
250
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" );
257         }
258 }
259
260 /****************************************************************************
261   Function called when a query for a WORKGROUP<1b> name succeeds.
262 ****************************************************************************/
263
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)
267 {
268         /* 
269          * Unfortunately, finding the IP address of the Domain Master Browser,
270          * as we have here, is not enough. We need to now do a sync to the
271          * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
272          * respond to the SMBSERVER name. To get this name from IP
273          * address we do a Node status request, and look for the first
274          * NAME<0x20> in the response, and take that as the server name.
275          * We also keep a cache of the Domain Master Browser name for this
276          * workgroup in the Workgroup struct, so that if the same IP addess
277          * is returned every time, we don't need to do the node status
278          * request.
279          */
280
281         struct work_record *work;
282         struct nmb_name nmbname;
283         struct userdata_struct *userdata;
284         size_t size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
285         unstring qname;
286
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);
292                 }
293         return;
294   }
295
296   /* First check if we already have a dmb for this workgroup. */
297
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 );
302
303                 /* Now synchronise lists with the domain master browser. */
304                 sync_with_dmb(work);
305                 return;
306         } else {
307                 zero_ip_v4(&work->dmb_addr);
308         }
309
310         /* Now initiate the node status request. */
311
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.
317          */
318
319         make_nmb_name(&nmbname,work->work_group,0x1b);
320
321         /* Put the workgroup name into the userdata so we know
322          what workgroup we're talking to when the reply comes
323          back. */
324
325         /* Setup the userdata_struct - this is copied so we can use
326         a stack variable for this. */
327
328         if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {
329                 DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
330                 return;
331         }
332
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));
337
338         node_status( subrec, &nmbname, answer_ip, 
339                 domain_master_node_status_success,
340                 domain_master_node_status_fail,
341                 userdata);
342
343         zero_free(userdata, size);
344 }
345
346 /****************************************************************************
347   Function called when a query for a WORKGROUP<1b> name fails.
348   ****************************************************************************/
349
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)
353 {
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" );
360         }
361 }
362
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 **************************************************************************/
368
369 void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
370                                                    struct work_record *work)
371 {
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" );
377                 }
378                 return;
379         }
380
381         /* First, query for the WORKGROUP<1b> name from the WINS server. */
382         query_name(unicast_subnet, work->work_group, 0x1b,
383              find_domain_master_name_query_success,
384              find_domain_master_name_query_fail,
385              NULL);
386 }
387
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.
391
392   Note that adding the workgroup name is enough for this workgroup to be
393   browsable by clients, as clients query the WINS server or broadcast 
394   nets for the WORKGROUP<1b> name when they want to browse a workgroup
395   they are not in. We do not need to do a sync with this Domain Master
396   Browser in order for our browse clients to see machines in this workgroup.
397   JRA.
398 ****************************************************************************/
399
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)
404 {
405         unstring server_name;
406
407         server_name[0] = 0;
408
409         if( DEBUGLVL( 3 ) ) {
410                 dbgtext( "get_domain_master_name_node_status_success:\n" );
411                 dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
412         }
413
414         /* 
415          * Go through the list of names found at answers->rdata and look for
416          * the first WORKGROUP<0x1b> name.
417          */
418
419         if (answers->rdlength > 0) {
420                 char *p = answers->rdata;
421                 int numnames = CVAL(p, 0);
422
423                 p += 1;
424
425                 while (numnames--) {
426                         unstring qname;
427                         uint16_t nb_flags;
428                         int name_type;
429
430                         pull_ascii_nstring(qname, sizeof(qname), p);
431                         name_type = CVAL(p,15);
432                         nb_flags = get_nb_flags(&p[16]);
433                         trim_char(qname,'\0',' ');
434
435                         p += 18;
436
437                         if(!(nb_flags & NB_GROUP) && (name_type == 0x00) && 
438                                         server_name[0] == 0) {
439                                 /* this is almost certainly the server netbios name */
440                                 strlcpy(server_name, qname, sizeof(server_name));
441                                 continue;
442                         }
443
444                         if(!(nb_flags & NB_GROUP) && (name_type == 0x1b)) {
445                                 struct work_record *work;
446
447                                 if( DEBUGLVL( 5 ) ) {
448                                         dbgtext( "get_domain_master_name_node_status_success:\n" );
449                                         dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
450                                         dbgtext( "is a domain master browser for workgroup " );
451                                         dbgtext( "%s. Adding this name.\n", qname );
452                                 }
453
454                                 /* 
455                                  * If we don't already know about this workgroup, add it
456                                  * to the workgroup list on the unicast_subnet.
457                                  */
458
459                                 work = find_workgroup_on_subnet( subrec, qname);
460                                 if (work == NULL) {
461                                         struct nmb_name nmbname;
462                                         /* 
463                                          * Add it - with an hour in the cache.
464                                          */
465                                         work = create_workgroup_on_subnet(subrec, qname, 60*60);
466                                         if (work == NULL) {
467                                                 return;
468                                         }
469
470                                         /* remember who the master is */
471                                         strlcpy(work->local_master_browser_name,
472                                                 server_name,
473                                                 sizeof(work->local_master_browser_name));
474                                         make_nmb_name(&nmbname, server_name, 0x20);
475                                         work->dmb_name = nmbname;
476                                         work->dmb_addr = from_ip;
477                                 }
478                                 break;
479                         }
480                 }
481         } else if( DEBUGLVL( 1 ) ) {
482                 dbgtext( "get_domain_master_name_node_status_success:\n" );
483                 dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
484                 dbgtext( "%s.\n", inet_ntoa(from_ip) );
485         }
486 }
487
488 /****************************************************************************
489   Function called when a node status query to a domain master browser IP fails.
490 ****************************************************************************/
491
492 static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
493                        struct response_record *rrec)
494 {
495         if( DEBUGLVL( 2 ) ) {
496                 dbgtext( "get_domain_master_name_node_status_fail:\n" );
497                 dbgtext( "Doing a node status request to the domain master browser " );
498                 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
499                 dbgtext( "Cannot get workgroup name.\n" );
500         }
501 }
502
503 /****************************************************************************
504   Function called when a query for *<1b> name succeeds.
505 ****************************************************************************/
506
507 static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
508                         struct userdata_struct *userdata_in,
509                         struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
510 {
511         /* 
512          * We now have a list of all the domain master browsers for all workgroups
513          * that have registered with the WINS server. Now do a node status request
514          * to each one and look for the first 1b name in the reply. This will be
515          * the workgroup name that we will add to the unicast subnet as a 'non-local'
516          * workgroup.
517          */
518
519         struct nmb_name nmbname;
520         struct in_addr send_ip;
521         int i;
522
523         if( DEBUGLVL( 5 ) ) {
524                 dbgtext( "find_all_domain_master_names_query_succes:\n" );
525                 dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
526                 dbgtext( "IP addresses for Domain Master Browsers.\n" );
527         }
528
529         for(i = 0; i < rrec->rdlength / 6; i++) {
530                 /* Initiate the node status requests. */
531                 make_nmb_name(&nmbname, "*", 0);
532
533                 putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
534
535                 /* 
536                  * Don't send node status requests to ourself.
537                  */
538
539                 if(ismyip_v4( send_ip )) {
540                         if( DEBUGLVL( 5 ) ) {
541                                 dbgtext( "find_all_domain_master_names_query_succes:\n" );
542                                 dbgtext( "Not sending node status to our own IP " );
543                                 dbgtext( "%s.\n", inet_ntoa(send_ip) );
544                         }
545                         continue;
546                 }
547
548                 if( DEBUGLVL( 5 ) ) {
549                         dbgtext( "find_all_domain_master_names_query_success:\n" );
550                         dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
551                 }
552
553                 node_status( subrec, &nmbname, send_ip, 
554                                 get_domain_master_name_node_status_success,
555                                 get_domain_master_name_node_status_fail,
556                                 NULL);
557         }
558 }
559
560 /****************************************************************************
561   Function called when a query for *<1b> name fails.
562   ****************************************************************************/
563 static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
564                                     struct response_record *rrec,
565                                     struct nmb_name *question_name, int fail_code)
566 {
567         if( DEBUGLVL( 10 ) ) {
568                 dbgtext( "find_domain_master_name_query_fail:\n" );
569                 dbgtext( "WINS server did not reply to a query for name " );
570                 dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
571                 dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
572         }
573 }
574
575 /****************************************************************************
576  If we are a domain master browser on the unicast subnet, do a query to the
577  WINS server for the *<1b> name. This will only work to a Samba WINS server,
578  so ignore it if we fail. If we succeed, contact each of the IP addresses in
579  turn and do a node status request to them. If this succeeds then look for a
580  <1b> name in the reply - this is the workgroup name. Add this to the unicast
581  subnet. This is expensive, so we only do this every 15 minutes.
582 **************************************************************************/
583
584 void collect_all_workgroup_names_from_wins_server(time_t t)
585 {
586         static time_t lastrun = 0;
587         struct work_record *work;
588
589         /* Only do this if we are using a WINS server. */
590         if(we_are_a_wins_client() == False)
591                 return;
592
593         /* Check to see if we are a domain master browser on the unicast subnet. */
594         if((work = find_workgroup_on_subnet( unicast_subnet, lp_workgroup())) == NULL) {
595                 if( DEBUGLVL( 0 ) ) {
596                         dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
597                         dbgtext( "Cannot find my workgroup %s ", lp_workgroup() );
598                         dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
599                 }
600                 return;
601         }
602
603         if(!AM_DOMAIN_MASTER_BROWSER(work))
604                 return;
605
606         if ((lastrun != 0) && (t < lastrun + (15 * 60)))
607                 return;
608      
609         lastrun = t;
610
611         /* First, query for the *<1b> name from the WINS server. */
612         query_name(unicast_subnet, "*", 0x1b,
613                 find_all_domain_master_names_query_success,
614                 find_all_domain_master_names_query_fail,
615                 NULL);
616
617
618
619 /****************************************************************************
620  If we are a domain master browser on the unicast subnet, do a regular sync
621  with all other DMBs that we know of on that subnet.
622
623 To prevent exponential network traffic with large numbers of workgroups
624 we use a randomised system where sync probability is inversely proportional
625 to the number of known workgroups
626 **************************************************************************/
627
628 void sync_all_dmbs(time_t t)
629 {
630         static time_t lastrun = 0;
631         struct work_record *work;
632         int count=0;
633
634         /* Only do this if we are using a WINS server. */
635         if(we_are_a_wins_client() == False)
636                 return;
637
638         /* Check to see if we are a domain master browser on the
639            unicast subnet. */
640         work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup());
641         if (!work)
642                 return;
643
644         if (!AM_DOMAIN_MASTER_BROWSER(work))
645                 return;
646
647         if ((lastrun != 0) && (t < lastrun + (5 * 60)))
648                 return;
649      
650         /* count how many syncs we might need to do */
651         for (work=unicast_subnet->workgrouplist; work; work = work->next) {
652                 if (strcmp(lp_workgroup(), work->work_group)) {
653                         count++;
654                 }
655         }
656
657         /* leave if we don't have to do any syncs */
658         if (count == 0) {
659                 return;
660         }
661
662         /* sync with a probability of 1/count */
663         for (work=unicast_subnet->workgrouplist; work; work = work->next) {
664                 if (strcmp(lp_workgroup(), work->work_group)) {
665                         unstring dmb_name;
666
667                         if (((unsigned)sys_random()) % count != 0)
668                                 continue;
669
670                         lastrun = t;
671
672                         if (!work->dmb_name.name[0]) {
673                                 /* we don't know the DMB - assume it is
674                                    the same as the unicast local master */
675                                 make_nmb_name(&work->dmb_name, 
676                                               work->local_master_browser_name,
677                                               0x20);
678                         }
679
680                         pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
681
682                         DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
683                                  dmb_name, inet_ntoa(work->dmb_addr)));
684
685                         sync_browse_lists(work, 
686                                           dmb_name,
687                                           work->dmb_name.name_type, 
688                                           work->dmb_addr, False, False);
689                 }
690         }
691 }