Check error returns from strupper_m() (in all reasonable places).
[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->rdata != NULL) {
198                 char *p = answers->rdata;
199                 int numnames = CVAL(p, 0);
200
201                 p += 1;
202
203                 while (numnames--) {
204                         unstring qname;
205                         uint16 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         struct work_record *work;
406         unstring server_name;
407
408         server_name[0] = 0;
409
410         if( DEBUGLVL( 3 ) ) {
411                 dbgtext( "get_domain_master_name_node_status_success:\n" );
412                 dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
413         }
414
415         /* 
416          * Go through the list of names found at answers->rdata and look for
417          * the first WORKGROUP<0x1b> name.
418          */
419
420         if(answers->rdata != NULL) {
421                 char *p = answers->rdata;
422                 int numnames = CVAL(p, 0);
423
424                 p += 1;
425
426                 while (numnames--) {
427                         unstring qname;
428                         uint16 nb_flags;
429                         int name_type;
430
431                         pull_ascii_nstring(qname, sizeof(qname), p);
432                         name_type = CVAL(p,15);
433                         nb_flags = get_nb_flags(&p[16]);
434                         trim_char(qname,'\0',' ');
435
436                         p += 18;
437
438                         if(!(nb_flags & NB_GROUP) && (name_type == 0x00) && 
439                                         server_name[0] == 0) {
440                                 /* this is almost certainly the server netbios name */
441                                 strlcpy(server_name, qname, sizeof(server_name));
442                                 continue;
443                         }
444
445                         if(!(nb_flags & NB_GROUP) && (name_type == 0x1b)) {
446                                 if( DEBUGLVL( 5 ) ) {
447                                         dbgtext( "get_domain_master_name_node_status_success:\n" );
448                                         dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
449                                         dbgtext( "is a domain master browser for workgroup " );
450                                         dbgtext( "%s. Adding this name.\n", qname );
451                                 }
452
453                                 /* 
454                                  * If we don't already know about this workgroup, add it
455                                  * to the workgroup list on the unicast_subnet.
456                                  */
457
458                                 if((work = find_workgroup_on_subnet( subrec, qname)) == NULL) {
459                                         struct nmb_name nmbname;
460                                         /* 
461                                          * Add it - with an hour in the cache.
462                                          */
463                                         if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
464                                                 return;
465
466                                         /* remember who the master is */
467                                         strlcpy(work->local_master_browser_name,
468                                                 server_name,
469                                                 sizeof(work->local_master_browser_name));
470                                         make_nmb_name(&nmbname, server_name, 0x20);
471                                         work->dmb_name = nmbname;
472                                         work->dmb_addr = from_ip;
473                                 }
474                                 break;
475                         }
476                 }
477         } else if( DEBUGLVL( 1 ) ) {
478                 dbgtext( "get_domain_master_name_node_status_success:\n" );
479                 dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
480                 dbgtext( "%s.\n", inet_ntoa(from_ip) );
481         }
482 }
483
484 /****************************************************************************
485   Function called when a node status query to a domain master browser IP fails.
486 ****************************************************************************/
487
488 static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
489                        struct response_record *rrec)
490 {
491         if( DEBUGLVL( 2 ) ) {
492                 dbgtext( "get_domain_master_name_node_status_fail:\n" );
493                 dbgtext( "Doing a node status request to the domain master browser " );
494                 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
495                 dbgtext( "Cannot get workgroup name.\n" );
496         }
497 }
498
499 /****************************************************************************
500   Function called when a query for *<1b> name succeeds.
501 ****************************************************************************/
502
503 static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
504                         struct userdata_struct *userdata_in,
505                         struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
506 {
507         /* 
508          * We now have a list of all the domain master browsers for all workgroups
509          * that have registered with the WINS server. Now do a node status request
510          * to each one and look for the first 1b name in the reply. This will be
511          * the workgroup name that we will add to the unicast subnet as a 'non-local'
512          * workgroup.
513          */
514
515         struct nmb_name nmbname;
516         struct in_addr send_ip;
517         int i;
518
519         if( DEBUGLVL( 5 ) ) {
520                 dbgtext( "find_all_domain_master_names_query_succes:\n" );
521                 dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
522                 dbgtext( "IP addresses for Domain Master Browsers.\n" );
523         }
524
525         for(i = 0; i < rrec->rdlength / 6; i++) {
526                 /* Initiate the node status requests. */
527                 make_nmb_name(&nmbname, "*", 0);
528
529                 putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
530
531                 /* 
532                  * Don't send node status requests to ourself.
533                  */
534
535                 if(ismyip_v4( send_ip )) {
536                         if( DEBUGLVL( 5 ) ) {
537                                 dbgtext( "find_all_domain_master_names_query_succes:\n" );
538                                 dbgtext( "Not sending node status to our own IP " );
539                                 dbgtext( "%s.\n", inet_ntoa(send_ip) );
540                         }
541                         continue;
542                 }
543
544                 if( DEBUGLVL( 5 ) ) {
545                         dbgtext( "find_all_domain_master_names_query_success:\n" );
546                         dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
547                 }
548
549                 node_status( subrec, &nmbname, send_ip, 
550                                 get_domain_master_name_node_status_success,
551                                 get_domain_master_name_node_status_fail,
552                                 NULL);
553         }
554 }
555
556 /****************************************************************************
557   Function called when a query for *<1b> name fails.
558   ****************************************************************************/
559 static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
560                                     struct response_record *rrec,
561                                     struct nmb_name *question_name, int fail_code)
562 {
563         if( DEBUGLVL( 10 ) ) {
564                 dbgtext( "find_domain_master_name_query_fail:\n" );
565                 dbgtext( "WINS server did not reply to a query for name " );
566                 dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
567                 dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
568         }
569 }
570
571 /****************************************************************************
572  If we are a domain master browser on the unicast subnet, do a query to the
573  WINS server for the *<1b> name. This will only work to a Samba WINS server,
574  so ignore it if we fail. If we succeed, contact each of the IP addresses in
575  turn and do a node status request to them. If this succeeds then look for a
576  <1b> name in the reply - this is the workgroup name. Add this to the unicast
577  subnet. This is expensive, so we only do this every 15 minutes.
578 **************************************************************************/
579
580 void collect_all_workgroup_names_from_wins_server(time_t t)
581 {
582         static time_t lastrun = 0;
583         struct work_record *work;
584
585         /* Only do this if we are using a WINS server. */
586         if(we_are_a_wins_client() == False)
587                 return;
588
589         /* Check to see if we are a domain master browser on the unicast subnet. */
590         if((work = find_workgroup_on_subnet( unicast_subnet, lp_workgroup())) == NULL) {
591                 if( DEBUGLVL( 0 ) ) {
592                         dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
593                         dbgtext( "Cannot find my workgroup %s ", lp_workgroup() );
594                         dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
595                 }
596                 return;
597         }
598
599         if(!AM_DOMAIN_MASTER_BROWSER(work))
600                 return;
601
602         if ((lastrun != 0) && (t < lastrun + (15 * 60)))
603                 return;
604      
605         lastrun = t;
606
607         /* First, query for the *<1b> name from the WINS server. */
608         query_name(unicast_subnet, "*", 0x1b,
609                 find_all_domain_master_names_query_success,
610                 find_all_domain_master_names_query_fail,
611                 NULL);
612
613
614
615 /****************************************************************************
616  If we are a domain master browser on the unicast subnet, do a regular sync
617  with all other DMBs that we know of on that subnet.
618
619 To prevent exponential network traffic with large numbers of workgroups
620 we use a randomised system where sync probability is inversely proportional
621 to the number of known workgroups
622 **************************************************************************/
623
624 void sync_all_dmbs(time_t t)
625 {
626         static time_t lastrun = 0;
627         struct work_record *work;
628         int count=0;
629
630         /* Only do this if we are using a WINS server. */
631         if(we_are_a_wins_client() == False)
632                 return;
633
634         /* Check to see if we are a domain master browser on the
635            unicast subnet. */
636         work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup());
637         if (!work)
638                 return;
639
640         if (!AM_DOMAIN_MASTER_BROWSER(work))
641                 return;
642
643         if ((lastrun != 0) && (t < lastrun + (5 * 60)))
644                 return;
645      
646         /* count how many syncs we might need to do */
647         for (work=unicast_subnet->workgrouplist; work; work = work->next) {
648                 if (strcmp(lp_workgroup(), work->work_group)) {
649                         count++;
650                 }
651         }
652
653         /* leave if we don't have to do any syncs */
654         if (count == 0) {
655                 return;
656         }
657
658         /* sync with a probability of 1/count */
659         for (work=unicast_subnet->workgrouplist; work; work = work->next) {
660                 if (strcmp(lp_workgroup(), work->work_group)) {
661                         unstring dmb_name;
662
663                         if (((unsigned)sys_random()) % count != 0)
664                                 continue;
665
666                         lastrun = t;
667
668                         if (!work->dmb_name.name[0]) {
669                                 /* we don't know the DMB - assume it is
670                                    the same as the unicast local master */
671                                 make_nmb_name(&work->dmb_name, 
672                                               work->local_master_browser_name,
673                                               0x20);
674                         }
675
676                         pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
677
678                         DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
679                                  dmb_name, inet_ntoa(work->dmb_addr)));
680
681                         sync_browse_lists(work, 
682                                           dmb_name,
683                                           work->dmb_name.name_type, 
684                                           work->dmb_addr, False, False);
685                 }
686         }
687 }