root/source3/nmbd/nmbd_browsesync.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sync_with_lmb
  2. dmb_expire_and_sync_browser_lists
  3. announce_local_master_browser_to_domain_master_browser
  4. sync_with_dmb
  5. domain_master_node_status_success
  6. domain_master_node_status_fail
  7. find_domain_master_name_query_success
  8. find_domain_master_name_query_fail
  9. announce_and_sync_with_domain_master_browser
  10. get_domain_master_name_node_status_success
  11. get_domain_master_name_node_status_fail
  12. find_all_domain_master_names_query_success
  13. find_all_domain_master_names_query_fail
  14. collect_all_workgroup_names_from_wins_server
  15. sync_all_dmbs

   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 
  25 /* This is our local master browser list database. */
  26 extern struct browse_cache_record *lmb_browserlist;
  27 
  28 /****************************************************************************
  29 As a domain master browser, do a sync with a local master browser.
  30 **************************************************************************/
  31 
  32 static void sync_with_lmb(struct browse_cache_record *browc)
     /* [<][>][^][v][top][bottom][index][help] */
  33 {                     
  34         struct work_record *work;
  35 
  36         if( !(work = find_workgroup_on_subnet(unicast_subnet, browc->work_group)) ) {
  37                 if( DEBUGLVL( 0 ) ) {
  38                         dbgtext( "sync_with_lmb:\n" );
  39                         dbgtext( "Failed to get a workgroup for a local master browser " );
  40                         dbgtext( "cache entry workgroup " );
  41                         dbgtext( "%s, server %s\n", browc->work_group, browc->lmb_name );
  42                 }
  43                 return;
  44         }
  45 
  46         /* We should only be doing this if we are a domain master browser for
  47                 the given workgroup. Ensure this is so. */
  48 
  49         if(!AM_DOMAIN_MASTER_BROWSER(work)) {
  50                 if( DEBUGLVL( 0 ) ) {
  51                         dbgtext( "sync_with_lmb:\n" );
  52                         dbgtext( "We are trying to sync with a local master browser " );
  53                         dbgtext( "%s for workgroup %s\n", browc->lmb_name, browc->work_group );
  54                         dbgtext( "and we are not a domain master browser on this workgroup.\n" );
  55                         dbgtext( "Error!\n" );
  56                 }
  57                 return;
  58         }
  59 
  60         if( DEBUGLVL( 2 ) ) {
  61                 dbgtext( "sync_with_lmb:\n" );
  62                 dbgtext( "Initiating sync with local master browser " );
  63                 dbgtext( "%s<0x20> at IP %s ", browc->lmb_name, inet_ntoa(browc->ip) );
  64                 dbgtext( "for workgroup %s\n", browc->work_group );
  65         }
  66 
  67         sync_browse_lists(work, browc->lmb_name, 0x20, browc->ip, True, True);
  68 
  69         browc->sync_time += (CHECK_TIME_DMB_TO_LMB_SYNC * 60);
  70 }
  71 
  72 /****************************************************************************
  73 Sync or expire any local master browsers.
  74 **************************************************************************/
  75 
  76 void dmb_expire_and_sync_browser_lists(time_t t)
     /* [<][>][^][v][top][bottom][index][help] */
  77 {
  78         static time_t last_run = 0;
  79         struct browse_cache_record *browc;
  80 
  81         /* Only do this every 20 seconds. */  
  82         if (t - last_run < 20) 
  83                 return;
  84 
  85         last_run = t;
  86 
  87         expire_lmb_browsers(t);
  88 
  89         for( browc = lmb_browserlist; browc; browc = browc->next ) {
  90                 if (browc->sync_time < t)
  91                         sync_with_lmb(browc);
  92         }
  93 }
  94 
  95 /****************************************************************************
  96 As a local master browser, send an announce packet to the domain master browser.
  97 **************************************************************************/
  98 
  99 static void announce_local_master_browser_to_domain_master_browser( struct work_record *work)
     /* [<][>][^][v][top][bottom][index][help] */
 100 {
 101         char outbuf[1024];
 102         unstring myname;
 103         unstring dmb_name;
 104         char *p;
 105 
 106         if(ismyip_v4(work->dmb_addr)) {
 107                 if( DEBUGLVL( 2 ) ) {
 108                         dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
 109                         dbgtext( "We are both a domain and a local master browser for " );
 110                         dbgtext( "workgroup %s.  ", work->work_group );
 111                         dbgtext( "Do not announce to ourselves.\n" );
 112                 }
 113                 return;
 114         }
 115 
 116         memset(outbuf,'\0',sizeof(outbuf));
 117         p = outbuf;
 118         SCVAL(p,0,ANN_MasterAnnouncement);
 119         p++;
 120 
 121         unstrcpy(myname, global_myname());
 122         strupper_m(myname);
 123         myname[15]='\0';
 124         /* The call below does CH_UNIX -> CH_DOS conversion. JRA */
 125         push_ascii(p, myname, sizeof(outbuf)-PTR_DIFF(p,outbuf)-1, STR_TERMINATE);
 126 
 127         p = skip_string(outbuf,sizeof(outbuf),p);
 128 
 129         if( DEBUGLVL( 4 ) ) {
 130                 dbgtext( "announce_local_master_browser_to_domain_master_browser:\n" );
 131                 dbgtext( "Sending local master announce to " );
 132                 dbgtext( "%s for workgroup %s.\n", nmb_namestr(&work->dmb_name),
 133                                         work->work_group );
 134         }
 135 
 136         /* Target name for send_mailslot must be in UNIX charset. */
 137         pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
 138         send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
 139                 global_myname(), 0x0, dmb_name, 0x0,
 140                 work->dmb_addr, FIRST_SUBNET->myip, DGRAM_PORT);
 141 }
 142 
 143 /****************************************************************************
 144 As a local master browser, do a sync with a domain master browser.
 145 **************************************************************************/
 146 
 147 static void sync_with_dmb(struct work_record *work)
     /* [<][>][^][v][top][bottom][index][help] */
 148 {
 149         unstring dmb_name;
 150 
 151         if( DEBUGLVL( 2 ) ) {
 152                 dbgtext( "sync_with_dmb:\n" );
 153                 dbgtext( "Initiating sync with domain master browser " );
 154                 dbgtext( "%s ", nmb_namestr(&work->dmb_name) );
 155                 dbgtext( "at IP %s ", inet_ntoa(work->dmb_addr) );
 156                 dbgtext( "for workgroup %s\n", work->work_group );
 157         }
 158 
 159         pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
 160         sync_browse_lists(work, dmb_name, work->dmb_name.name_type, 
 161                 work->dmb_addr, False, True);
 162 }
 163 
 164 /****************************************************************************
 165   Function called when a node status query to a domain master browser IP succeeds.
 166 ****************************************************************************/
 167 
 168 static void domain_master_node_status_success(struct subnet_record *subrec,
     /* [<][>][^][v][top][bottom][index][help] */
 169                                               struct userdata_struct *userdata,
 170                                               struct res_rec *answers,
 171                                               struct in_addr from_ip)
 172 {
 173         struct work_record *work = find_workgroup_on_subnet( subrec, userdata->data);
 174 
 175         if( work == NULL ) {
 176                 if( DEBUGLVL( 0 ) ) {
 177                         dbgtext( "domain_master_node_status_success:\n" );
 178                         dbgtext( "Unable to find workgroup " );
 179                         dbgtext( "%s on subnet %s.\n", userdata->data, subrec->subnet_name );
 180                 }
 181                 return;
 182         }
 183 
 184         if( DEBUGLVL( 3 ) ) {
 185                 dbgtext( "domain_master_node_status_success:\n" );
 186                 dbgtext( "Success in node status for workgroup " );
 187                 dbgtext( "%s from ip %s\n", work->work_group, inet_ntoa(from_ip) );
 188         }
 189 
 190   /* Go through the list of names found at answers->rdata and look for
 191      the first SERVER<0x20> name. */
 192 
 193         if(answers->rdata != NULL) {
 194                 char *p = answers->rdata;
 195                 int numnames = CVAL(p, 0);
 196 
 197                 p += 1;
 198 
 199                 while (numnames--) {
 200                         unstring qname;
 201                         uint16 nb_flags;
 202                         int name_type;
 203 
 204                         pull_ascii_nstring(qname, sizeof(qname), p);
 205                         name_type = CVAL(p,15);
 206                         nb_flags = get_nb_flags(&p[16]);
 207                         trim_char(qname,'\0',' ');
 208 
 209                         p += 18;
 210 
 211                         if(!(nb_flags & NB_GROUP) && (name_type == 0x20)) {
 212                                 struct nmb_name nmbname;
 213 
 214                                 make_nmb_name(&nmbname, qname, name_type);
 215 
 216                                 /* Copy the dmb name and IP address
 217                                         into the workgroup struct. */
 218 
 219                                 work->dmb_name = nmbname;
 220                                 putip((char *)&work->dmb_addr, &from_ip);
 221 
 222                                 /* Do the local master browser announcement to the domain
 223                                         master browser name and IP. */
 224                                 announce_local_master_browser_to_domain_master_browser( work );
 225 
 226                                 /* Now synchronise lists with the domain master browser. */
 227                                 sync_with_dmb(work);
 228                                 break;
 229                         }
 230                 }
 231         } else if( DEBUGLVL( 0 ) ) {
 232                 dbgtext( "domain_master_node_status_success:\n" );
 233                 dbgtext( "Failed to find a SERVER<0x20> name in reply from IP " );
 234                 dbgtext( "%s.\n", inet_ntoa(from_ip) );
 235         }
 236 }
 237 
 238 /****************************************************************************
 239   Function called when a node status query to a domain master browser IP fails.
 240 ****************************************************************************/
 241 
 242 static void domain_master_node_status_fail(struct subnet_record *subrec,
     /* [<][>][^][v][top][bottom][index][help] */
 243                        struct response_record *rrec)
 244 {
 245         struct userdata_struct *userdata = rrec->userdata;
 246 
 247         if( DEBUGLVL( 0 ) ) {
 248                 dbgtext( "domain_master_node_status_fail:\n" );
 249                 dbgtext( "Doing a node status request to the domain master browser\n" );
 250                 dbgtext( "for workgroup %s ", userdata ? userdata->data : "NULL" );
 251                 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
 252                 dbgtext( "Cannot sync browser lists.\n" );
 253         }
 254 }
 255 
 256 /****************************************************************************
 257   Function called when a query for a WORKGROUP<1b> name succeeds.
 258 ****************************************************************************/
 259 
 260 static void find_domain_master_name_query_success(struct subnet_record *subrec,
     /* [<][>][^][v][top][bottom][index][help] */
 261                         struct userdata_struct *userdata_in,
 262                         struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
 263 {
 264         /* 
 265          * Unfortunately, finding the IP address of the Domain Master Browser,
 266          * as we have here, is not enough. We need to now do a sync to the
 267          * SERVERNAME<0x20> NetBIOS name, as only recent NT servers will
 268          * respond to the SMBSERVER name. To get this name from IP
 269          * address we do a Node status request, and look for the first
 270          * NAME<0x20> in the response, and take that as the server name.
 271          * We also keep a cache of the Domain Master Browser name for this
 272          * workgroup in the Workgroup struct, so that if the same IP addess
 273          * is returned every time, we don't need to do the node status
 274          * request.
 275          */
 276 
 277         struct work_record *work;
 278         struct nmb_name nmbname;
 279         struct userdata_struct *userdata;
 280         size_t size = sizeof(struct userdata_struct) + sizeof(fstring)+1;
 281         unstring qname;
 282 
 283         pull_ascii_nstring(qname, sizeof(qname), q_name->name);
 284         if( !(work = find_workgroup_on_subnet(subrec, qname)) ) {
 285                 if( DEBUGLVL( 0 ) ) {
 286                         dbgtext( "find_domain_master_name_query_success:\n" );
 287                         dbgtext( "Failed to find workgroup %s\n", qname);
 288                 }
 289         return;
 290   }
 291 
 292   /* First check if we already have a dmb for this workgroup. */
 293 
 294         if(!is_zero_ip_v4(work->dmb_addr) && ip_equal_v4(work->dmb_addr, answer_ip)) {
 295                 /* Do the local master browser announcement to the domain
 296                         master browser name and IP. */
 297                 announce_local_master_browser_to_domain_master_browser( work );
 298 
 299                 /* Now synchronise lists with the domain master browser. */
 300                 sync_with_dmb(work);
 301                 return;
 302         } else {
 303                 zero_ip_v4(&work->dmb_addr);
 304         }
 305 
 306         /* Now initiate the node status request. */
 307 
 308         /* We used to use the name "*",0x0 here, but some Windows
 309          * servers don't answer that name. However we *know* they
 310          * have the name workgroup#1b (as we just looked it up).
 311          * So do the node status request on this name instead.
 312          * Found at LBL labs. JRA.
 313          */
 314 
 315         make_nmb_name(&nmbname,work->work_group,0x1b);
 316 
 317         /* Put the workgroup name into the userdata so we know
 318          what workgroup we're talking to when the reply comes
 319          back. */
 320 
 321         /* Setup the userdata_struct - this is copied so we can use
 322         a stack variable for this. */
 323 
 324         if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {
 325                 DEBUG(0, ("find_domain_master_name_query_success: malloc fail.\n"));
 326                 return;
 327         }
 328 
 329         userdata->copy_fn = NULL;
 330         userdata->free_fn = NULL;
 331         userdata->userdata_len = strlen(work->work_group)+1;
 332         overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
 333 
 334         node_status( subrec, &nmbname, answer_ip, 
 335                 domain_master_node_status_success,
 336                 domain_master_node_status_fail,
 337                 userdata);
 338 
 339         zero_free(userdata, size);
 340 }
 341 
 342 /****************************************************************************
 343   Function called when a query for a WORKGROUP<1b> name fails.
 344   ****************************************************************************/
 345 
 346 static void find_domain_master_name_query_fail(struct subnet_record *subrec,
     /* [<][>][^][v][top][bottom][index][help] */
 347                                     struct response_record *rrec,
 348                                     struct nmb_name *question_name, int fail_code)
 349 {
 350         if( DEBUGLVL( 0 ) ) {
 351                 dbgtext( "find_domain_master_name_query_fail:\n" );
 352                 dbgtext( "Unable to find the Domain Master Browser name " );
 353                 dbgtext( "%s for the workgroup %s.\n",
 354                         nmb_namestr(question_name), question_name->name );
 355                 dbgtext( "Unable to sync browse lists in this workgroup.\n" );
 356         }
 357 }
 358 
 359 /****************************************************************************
 360 As a local master browser for a workgroup find the domain master browser
 361 name, announce ourselves as local master browser to it and then pull the
 362 full domain browse lists from it onto the given subnet.
 363 **************************************************************************/
 364 
 365 void announce_and_sync_with_domain_master_browser( struct subnet_record *subrec,
     /* [<][>][^][v][top][bottom][index][help] */
 366                                                    struct work_record *work)
 367 {
 368         /* Only do this if we are using a WINS server. */
 369         if(we_are_a_wins_client() == False) {
 370                 if( DEBUGLVL( 10 ) ) {
 371                         dbgtext( "announce_and_sync_with_domain_master_browser:\n" );
 372                         dbgtext( "Ignoring, as we are not a WINS client.\n" );
 373                 }
 374                 return;
 375         }
 376 
 377         /* First, query for the WORKGROUP<1b> name from the WINS server. */
 378         query_name(unicast_subnet, work->work_group, 0x1b,
 379              find_domain_master_name_query_success,
 380              find_domain_master_name_query_fail,
 381              NULL);
 382 }
 383 
 384 /****************************************************************************
 385   Function called when a node status query to a domain master browser IP succeeds.
 386   This function is only called on query to a Samba 1.9.18 or above WINS server.
 387 
 388   Note that adding the workgroup name is enough for this workgroup to be
 389   browsable by clients, as clients query the WINS server or broadcast 
 390   nets for the WORKGROUP<1b> name when they want to browse a workgroup
 391   they are not in. We do not need to do a sync with this Domain Master
 392   Browser in order for our browse clients to see machines in this workgroup.
 393   JRA.
 394 ****************************************************************************/
 395 
 396 static void get_domain_master_name_node_status_success(struct subnet_record *subrec,
     /* [<][>][^][v][top][bottom][index][help] */
 397                                               struct userdata_struct *userdata,
 398                                               struct res_rec *answers,
 399                                               struct in_addr from_ip)
 400 {
 401         struct work_record *work;
 402         unstring server_name;
 403 
 404         server_name[0] = 0;
 405 
 406         if( DEBUGLVL( 3 ) ) {
 407                 dbgtext( "get_domain_master_name_node_status_success:\n" );
 408                 dbgtext( "Success in node status from ip %s\n", inet_ntoa(from_ip) );
 409         }
 410 
 411         /* 
 412          * Go through the list of names found at answers->rdata and look for
 413          * the first WORKGROUP<0x1b> name.
 414          */
 415 
 416         if(answers->rdata != NULL) {
 417                 char *p = answers->rdata;
 418                 int numnames = CVAL(p, 0);
 419 
 420                 p += 1;
 421 
 422                 while (numnames--) {
 423                         unstring qname;
 424                         uint16 nb_flags;
 425                         int name_type;
 426 
 427                         pull_ascii_nstring(qname, sizeof(qname), p);
 428                         name_type = CVAL(p,15);
 429                         nb_flags = get_nb_flags(&p[16]);
 430                         trim_char(qname,'\0',' ');
 431 
 432                         p += 18;
 433 
 434                         if(!(nb_flags & NB_GROUP) && (name_type == 0x00) && 
 435                                         server_name[0] == 0) {
 436                                 /* this is almost certainly the server netbios name */
 437                                 unstrcpy(server_name, qname);
 438                                 continue;
 439                         }
 440 
 441                         if(!(nb_flags & NB_GROUP) && (name_type == 0x1b)) {
 442                                 if( DEBUGLVL( 5 ) ) {
 443                                         dbgtext( "get_domain_master_name_node_status_success:\n" );
 444                                         dbgtext( "%s(%s) ", server_name, inet_ntoa(from_ip) );
 445                                         dbgtext( "is a domain master browser for workgroup " );
 446                                         dbgtext( "%s. Adding this name.\n", qname );
 447                                 }
 448 
 449                                 /* 
 450                                  * If we don't already know about this workgroup, add it
 451                                  * to the workgroup list on the unicast_subnet.
 452                                  */
 453 
 454                                 if((work = find_workgroup_on_subnet( subrec, qname)) == NULL) {
 455                                         struct nmb_name nmbname;
 456                                         /* 
 457                                          * Add it - with an hour in the cache.
 458                                          */
 459                                         if(!(work= create_workgroup_on_subnet(subrec, qname, 60*60)))
 460                                                 return;
 461 
 462                                         /* remember who the master is */
 463                                         unstrcpy(work->local_master_browser_name, server_name);
 464                                         make_nmb_name(&nmbname, server_name, 0x20);
 465                                         work->dmb_name = nmbname;
 466                                         work->dmb_addr = from_ip;
 467                                 }
 468                                 break;
 469                         }
 470                 }
 471         } else if( DEBUGLVL( 0 ) ) {
 472                 dbgtext( "get_domain_master_name_node_status_success:\n" );
 473                 dbgtext( "Failed to find a WORKGROUP<0x1b> name in reply from IP " );
 474                 dbgtext( "%s.\n", inet_ntoa(from_ip) );
 475         }
 476 }
 477 
 478 /****************************************************************************
 479   Function called when a node status query to a domain master browser IP fails.
 480 ****************************************************************************/
 481 
 482 static void get_domain_master_name_node_status_fail(struct subnet_record *subrec,
     /* [<][>][^][v][top][bottom][index][help] */
 483                        struct response_record *rrec)
 484 {
 485         if( DEBUGLVL( 0 ) ) {
 486                 dbgtext( "get_domain_master_name_node_status_fail:\n" );
 487                 dbgtext( "Doing a node status request to the domain master browser " );
 488                 dbgtext( "at IP %s failed.\n", inet_ntoa(rrec->packet->ip) );
 489                 dbgtext( "Cannot get workgroup name.\n" );
 490         }
 491 }
 492 
 493 /****************************************************************************
 494   Function called when a query for *<1b> name succeeds.
 495 ****************************************************************************/
 496 
 497 static void find_all_domain_master_names_query_success(struct subnet_record *subrec,
     /* [<][>][^][v][top][bottom][index][help] */
 498                         struct userdata_struct *userdata_in,
 499                         struct nmb_name *q_name, struct in_addr answer_ip, struct res_rec *rrec)
 500 {
 501         /* 
 502          * We now have a list of all the domain master browsers for all workgroups
 503          * that have registered with the WINS server. Now do a node status request
 504          * to each one and look for the first 1b name in the reply. This will be
 505          * the workgroup name that we will add to the unicast subnet as a 'non-local'
 506          * workgroup.
 507          */
 508 
 509         struct nmb_name nmbname;
 510         struct in_addr send_ip;
 511         int i;
 512 
 513         if( DEBUGLVL( 5 ) ) {
 514                 dbgtext( "find_all_domain_master_names_query_succes:\n" );
 515                 dbgtext( "Got answer from WINS server of %d ", (rrec->rdlength / 6) );
 516                 dbgtext( "IP addresses for Domain Master Browsers.\n" );
 517         }
 518 
 519         for(i = 0; i < rrec->rdlength / 6; i++) {
 520                 /* Initiate the node status requests. */
 521                 make_nmb_name(&nmbname, "*", 0);
 522 
 523                 putip((char *)&send_ip, (char *)&rrec->rdata[(i*6) + 2]);
 524 
 525                 /* 
 526                  * Don't send node status requests to ourself.
 527                  */
 528 
 529                 if(ismyip_v4( send_ip )) {
 530                         if( DEBUGLVL( 5 ) ) {
 531                                 dbgtext( "find_all_domain_master_names_query_succes:\n" );
 532                                 dbgtext( "Not sending node status to our own IP " );
 533                                 dbgtext( "%s.\n", inet_ntoa(send_ip) );
 534                         }
 535                         continue;
 536                 }
 537 
 538                 if( DEBUGLVL( 5 ) ) {
 539                         dbgtext( "find_all_domain_master_names_query_success:\n" );
 540                         dbgtext( "Sending node status request to IP %s.\n", inet_ntoa(send_ip) );
 541                 }
 542 
 543                 node_status( subrec, &nmbname, send_ip, 
 544                                 get_domain_master_name_node_status_success,
 545                                 get_domain_master_name_node_status_fail,
 546                                 NULL);
 547         }
 548 }
 549 
 550 /****************************************************************************
 551   Function called when a query for *<1b> name fails.
 552   ****************************************************************************/
 553 static void find_all_domain_master_names_query_fail(struct subnet_record *subrec,
     /* [<][>][^][v][top][bottom][index][help] */
 554                                     struct response_record *rrec,
 555                                     struct nmb_name *question_name, int fail_code)
 556 {
 557         if( DEBUGLVL( 10 ) ) {
 558                 dbgtext( "find_domain_master_name_query_fail:\n" );
 559                 dbgtext( "WINS server did not reply to a query for name " );
 560                 dbgtext( "%s.\nThis means it ", nmb_namestr(question_name) );
 561                 dbgtext( "is probably not a Samba 1.9.18 or above WINS server.\n" );
 562         }
 563 }
 564 
 565 /****************************************************************************
 566  If we are a domain master browser on the unicast subnet, do a query to the
 567  WINS server for the *<1b> name. This will only work to a Samba WINS server,
 568  so ignore it if we fail. If we succeed, contact each of the IP addresses in
 569  turn and do a node status request to them. If this succeeds then look for a
 570  <1b> name in the reply - this is the workgroup name. Add this to the unicast
 571  subnet. This is expensive, so we only do this every 15 minutes.
 572 **************************************************************************/
 573 
 574 void collect_all_workgroup_names_from_wins_server(time_t t)
     /* [<][>][^][v][top][bottom][index][help] */
 575 {
 576         static time_t lastrun = 0;
 577         struct work_record *work;
 578 
 579         /* Only do this if we are using a WINS server. */
 580         if(we_are_a_wins_client() == False)
 581                 return;
 582 
 583         /* Check to see if we are a domain master browser on the unicast subnet. */
 584         if((work = find_workgroup_on_subnet( unicast_subnet, lp_workgroup())) == NULL) {
 585                 if( DEBUGLVL( 0 ) ) {
 586                         dbgtext( "collect_all_workgroup_names_from_wins_server:\n" );
 587                         dbgtext( "Cannot find my workgroup %s ", lp_workgroup() );
 588                         dbgtext( "on subnet %s.\n", unicast_subnet->subnet_name );
 589                 }
 590                 return;
 591         }
 592 
 593         if(!AM_DOMAIN_MASTER_BROWSER(work))
 594                 return;
 595 
 596         if ((lastrun != 0) && (t < lastrun + (15 * 60)))
 597                 return;
 598      
 599         lastrun = t;
 600 
 601         /* First, query for the *<1b> name from the WINS server. */
 602         query_name(unicast_subnet, "*", 0x1b,
 603                 find_all_domain_master_names_query_success,
 604                 find_all_domain_master_names_query_fail,
 605                 NULL);
 606 } 
 607 
 608 
 609 /****************************************************************************
 610  If we are a domain master browser on the unicast subnet, do a regular sync
 611  with all other DMBs that we know of on that subnet.
 612 
 613 To prevent exponential network traffic with large numbers of workgroups
 614 we use a randomised system where sync probability is inversely proportional
 615 to the number of known workgroups
 616 **************************************************************************/
 617 
 618 void sync_all_dmbs(time_t t)
     /* [<][>][^][v][top][bottom][index][help] */
 619 {
 620         static time_t lastrun = 0;
 621         struct work_record *work;
 622         int count=0;
 623 
 624         /* Only do this if we are using a WINS server. */
 625         if(we_are_a_wins_client() == False)
 626                 return;
 627 
 628         /* Check to see if we are a domain master browser on the
 629            unicast subnet. */
 630         work = find_workgroup_on_subnet(unicast_subnet, lp_workgroup());
 631         if (!work)
 632                 return;
 633 
 634         if (!AM_DOMAIN_MASTER_BROWSER(work))
 635                 return;
 636 
 637         if ((lastrun != 0) && (t < lastrun + (5 * 60)))
 638                 return;
 639      
 640         /* count how many syncs we might need to do */
 641         for (work=unicast_subnet->workgrouplist; work; work = work->next) {
 642                 if (strcmp(lp_workgroup(), work->work_group)) {
 643                         count++;
 644                 }
 645         }
 646 
 647         /* sync with a probability of 1/count */
 648         for (work=unicast_subnet->workgrouplist; work; work = work->next) {
 649                 if (strcmp(lp_workgroup(), work->work_group)) {
 650                         unstring dmb_name;
 651 
 652                         if (((unsigned)sys_random()) % count != 0)
 653                                 continue;
 654 
 655                         lastrun = t;
 656 
 657                         if (!work->dmb_name.name[0]) {
 658                                 /* we don't know the DMB - assume it is
 659                                    the same as the unicast local master */
 660                                 make_nmb_name(&work->dmb_name, 
 661                                               work->local_master_browser_name,
 662                                               0x20);
 663                         }
 664 
 665                         pull_ascii_nstring(dmb_name, sizeof(dmb_name), work->dmb_name.name);
 666 
 667                         DEBUG(3,("Initiating DMB<->DMB sync with %s(%s)\n",
 668                                  dmb_name, inet_ntoa(work->dmb_addr)));
 669 
 670                         sync_browse_lists(work, 
 671                                           dmb_name,
 672                                           work->dmb_name.name_type, 
 673                                           work->dmb_addr, False, False);
 674                 }
 675         }
 676 }

/* [<][>][^][v][top][bottom][index][help] */