LCOV - code coverage report
Current view: top level - source3/nmbd - nmbd_browsesync.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 13 263 4.9 %
Date: 2021-09-23 10:06:22 Functions: 3 15 20.0 %

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

Generated by: LCOV version 1.13