LCOV - code coverage report
Current view: top level - source3/nmbd - nmbd_become_dmb.c (source / functions) Hit Total Coverage
Test: coverage report for master 2b515b7d Lines: 47 110 42.7 %
Date: 2024-02-28 12:06:22 Functions: 5 8 62.5 %

          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 "../librpc/gen_ndr/svcctl.h"
      25             : #include "nmbd/nmbd.h"
      26             : 
      27             : extern uint16_t samba_nb_type; /* Samba's NetBIOS type. */
      28             : 
      29             : static void become_domain_master_browser_bcast(const char *);
      30             : 
      31             : /****************************************************************************
      32             :   Fail to become a Domain Master Browser on a subnet.
      33             :   ****************************************************************************/
      34             : 
      35           0 : static void become_domain_master_fail(struct subnet_record *subrec,
      36             :                                       struct response_record *rrec,
      37             :                                       struct nmb_name *fail_name)
      38             : {
      39             :         unstring failname;
      40             :         struct work_record *work;
      41             :         struct server_record *servrec;
      42             : 
      43           0 :         pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
      44           0 :         work = find_workgroup_on_subnet(subrec, failname);
      45           0 :         if(!work) {
      46           0 :                 DEBUG(0,("become_domain_master_fail: Error - cannot find \
      47             : workgroup %s on subnet %s\n", failname, subrec->subnet_name));
      48           0 :                 return;
      49             :         }
      50             : 
      51             :         /* Set the state back to DOMAIN_NONE. */
      52           0 :         work->dom_state = DOMAIN_NONE;
      53             : 
      54           0 :         if((servrec = find_server_in_workgroup( work, lp_netbios_name())) == NULL) {
      55           0 :                 DEBUG(0,("become_domain_master_fail: Error - cannot find server %s \
      56             : in workgroup %s on subnet %s\n",
      57             :                         lp_netbios_name(), work->work_group, subrec->subnet_name));
      58           0 :                 return;
      59             :         }
      60             : 
      61             :         /* Update our server status. */
      62           0 :         servrec->serv.type &= ~SV_TYPE_DOMAIN_MASTER;
      63             : 
      64             :         /* Tell the namelist writer to write out a change. */
      65           0 :         subrec->work_changed = True;
      66             : 
      67           0 :         DEBUG(0,("become_domain_master_fail: Failed to become a domain master browser for \
      68             : workgroup %s on subnet %s. Couldn't register name %s.\n",
      69             :                 work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
      70             : }
      71             : 
      72             : /****************************************************************************
      73             :   Become a Domain Master Browser on a subnet.
      74             :   ****************************************************************************/
      75             : 
      76          13 : static void become_domain_master_stage2(struct subnet_record *subrec, 
      77             :                                         struct userdata_struct *userdata,
      78             :                                         struct nmb_name *registered_name,
      79             :                                         uint16_t nb_flags,
      80             :                                         int ttl, struct in_addr registered_ip)
      81             : {
      82             :         unstring regname;
      83             :         struct work_record *work;
      84             :         struct server_record *servrec;
      85             : 
      86          13 :         pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
      87          13 :         work = find_workgroup_on_subnet( subrec, regname);
      88             : 
      89          13 :         if(!work) {
      90           0 :                 DEBUG(0,("become_domain_master_stage2: Error - cannot find \
      91             : workgroup %s on subnet %s\n", regname, subrec->subnet_name));
      92           0 :                 return;
      93             :         }
      94             : 
      95          13 :         if((servrec = find_server_in_workgroup( work, lp_netbios_name())) == NULL) {
      96           0 :                 DEBUG(0,("become_domain_master_stage2: Error - cannot find server %s \
      97             : in workgroup %s on subnet %s\n", 
      98             :                 lp_netbios_name(), regname, subrec->subnet_name));
      99           0 :                 work->dom_state = DOMAIN_NONE;
     100           0 :                 return;
     101             :         }
     102             : 
     103             :         /* Set the state in the workgroup structure. */
     104          13 :         work->dom_state = DOMAIN_MST; /* Become domain master. */
     105             : 
     106             :         /* Update our server status. */
     107          13 :         servrec->serv.type |= (SV_TYPE_NT|SV_TYPE_DOMAIN_MASTER);
     108             : 
     109             :         /* Tell the namelist writer to write out a change. */
     110          13 :         subrec->work_changed = True;
     111             : 
     112          13 :         if( DEBUGLVL( 0 ) ) {
     113          13 :                 dbgtext( "*****\n\nSamba server %s ", lp_netbios_name() );
     114          13 :                 dbgtext( "is now a domain master browser for " );
     115          13 :                 dbgtext( "workgroup %s ", work->work_group );
     116          13 :                 dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
     117             :         }
     118             : 
     119          13 :         if( subrec == unicast_subnet ) {
     120             :                 struct nmb_name nmbname;
     121             :                 struct in_addr my_first_ip;
     122             :                 const struct in_addr *nip;
     123             : 
     124             :                 /* Put our name and first IP address into the 
     125             :                    workgroup struct as domain master browser. This
     126             :                    will stop us syncing with ourself if we are also
     127             :                    a local master browser. */
     128             : 
     129           0 :                 make_nmb_name(&nmbname, lp_netbios_name(), 0x20);
     130             : 
     131           0 :                 work->dmb_name = nmbname;
     132             : 
     133             :                 /* Pick the first interface IPv4 address as the domain master
     134             :                  * browser ip. */
     135           0 :                 nip = first_ipv4_iface();
     136           0 :                 if (!nip) {
     137           0 :                         DEBUG(0,("become_domain_master_stage2: "
     138             :                                 "Error. get_interface returned NULL\n"));
     139           0 :                         return;
     140             :                 }
     141           0 :                 my_first_ip = *nip;
     142             : 
     143           0 :                 putip((char *)&work->dmb_addr, &my_first_ip);
     144             : 
     145             :                 /* We successfully registered by unicast with the
     146             :                    WINS server.  We now expect to become the domain
     147             :                    master on the local subnets. If this fails, it's
     148             :                    probably a 1.9.16p2 to 1.9.16p11 server's fault.
     149             : 
     150             :                    This is a configuration issue that should be addressed
     151             :                    by the network administrator - you shouldn't have
     152             :                    several machines configured as a domain master browser
     153             :                    for the same WINS scope (except if they are 1.9.17 or
     154             :                    greater, and you know what you're doing.
     155             : 
     156             :                    see docs/DOMAIN.txt.
     157             : 
     158             :                 */
     159           0 :                 become_domain_master_browser_bcast(work->work_group);
     160             :         } else {
     161             :                 /*
     162             :                  * Now we are a domain master on a broadcast subnet, we need to add
     163             :                  * the WORKGROUP<1b> name to the unicast subnet so that we can answer
     164             :                  * unicast requests sent to this name. This bug wasn't found for a while
     165             :                  * as it is strange to have a DMB without using WINS. JRA.
     166             :                  */
     167          13 :                 insert_permanent_name_into_unicast(subrec, registered_name, nb_flags);
     168             :         }
     169             : }
     170             : 
     171             : /****************************************************************************
     172             :   Start the name registration process when becoming a Domain Master Browser
     173             :   on a subnet.
     174             : ****************************************************************************/
     175             : 
     176          14 : static void become_domain_master_stage1(struct subnet_record *subrec, const char *wg_name)
     177             : { 
     178             :         struct work_record *work;
     179             : 
     180          14 :         DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \
     181             : workgroup %s on subnet %s\n", wg_name, subrec->subnet_name));
     182             : 
     183             :         /* First, find the workgroup on the subnet. */
     184          14 :         if((work = find_workgroup_on_subnet( subrec, wg_name )) == NULL) {
     185           0 :                 DEBUG(0,("become_domain_master_stage1: Error - unable to find workgroup %s on subnet %s.\n",
     186             :                         wg_name, subrec->subnet_name));
     187           0 :                 return;
     188             :         }
     189             : 
     190          14 :         DEBUG(3,("become_domain_master_stage1: go to first stage: register <1b> name\n"));
     191          14 :         work->dom_state = DOMAIN_WAIT;
     192             : 
     193             :         /* WORKGROUP<1b> is the domain master browser name. */
     194          14 :         register_name(subrec, work->work_group,0x1b,samba_nb_type,
     195             :                         become_domain_master_stage2,
     196             :                         become_domain_master_fail, NULL);
     197             : }
     198             : 
     199             : /****************************************************************************
     200             :   Function called when a query for a WORKGROUP<1b> name succeeds.
     201             :   This is normally a fail condition as it means there is already
     202             :   a domain master browser for a workgroup and we were trying to
     203             :   become one.
     204             : ****************************************************************************/
     205             : 
     206           0 : static void become_domain_master_query_success(struct subnet_record *subrec,
     207             :                         struct userdata_struct *userdata,
     208             :                         struct nmb_name *nmbname, struct in_addr ip,
     209             :                         struct res_rec *rrec)
     210             : {
     211             :         unstring name;
     212             :         struct in_addr allones_ip;
     213             : 
     214           0 :         pull_ascii_nstring(name, sizeof(name), nmbname->name);
     215             : 
     216             :         /* If the given ip is not ours, then we can't become a domain
     217             :                 controller as the name is already registered.
     218             :         */
     219             : 
     220             :         /* BUG note. Samba 1.9.16p11 servers seem to return the broadcast
     221             :                 address or zero ip for this query. Pretend this is ok. */
     222             : 
     223           0 :         allones_ip.s_addr = htonl(INADDR_BROADCAST);
     224             : 
     225           0 :         if(ismyip_v4(ip) || ip_equal_v4(allones_ip, ip) || is_zero_ip_v4(ip)) {
     226           0 :                 if( DEBUGLVL( 3 ) ) {
     227           0 :                         dbgtext( "become_domain_master_query_success():\n" );
     228           0 :                         dbgtext( "Our address (%s) ", inet_ntoa(ip) );
     229           0 :                         dbgtext( "returned in query for name %s ", nmb_namestr(nmbname) );
     230           0 :                         dbgtext( "(domain master browser name) " );
     231           0 :                         dbgtext( "on subnet %s.\n", subrec->subnet_name );
     232           0 :                         dbgtext( "Continuing with domain master code.\n" );
     233             :                 }
     234             : 
     235           0 :                 become_domain_master_stage1(subrec, name);
     236             :         } else {
     237           0 :                 if( DEBUGLVL( 0 ) ) {
     238           0 :                         dbgtext( "become_domain_master_query_success:\n" );
     239           0 :                         dbgtext( "There is already a domain master browser at " );
     240           0 :                         dbgtext( "IP %s for workgroup %s ", inet_ntoa(ip), name );
     241           0 :                         dbgtext( "registered on subnet %s.\n", subrec->subnet_name );
     242             :                 }
     243             :         }
     244           0 : }
     245             : 
     246             : /****************************************************************************
     247             :   Function called when a query for a WORKGROUP<1b> name fails.
     248             :   This is normally a success condition as it then allows us to register
     249             :   our own Domain Master Browser name.
     250             :   ****************************************************************************/
     251             : 
     252          14 : static void become_domain_master_query_fail(struct subnet_record *subrec,
     253             :                                     struct response_record *rrec,
     254             :                                     struct nmb_name *question_name, int fail_code)
     255             : {
     256             :         unstring name;
     257             : 
     258             :         /* If the query was unicast, and the error is not NAM_ERR (name didn't exist),
     259             :                 then this is a failure. Otherwise, not finding the name is what we want. */
     260             : 
     261          14 :         if((subrec == unicast_subnet) && (fail_code != NAM_ERR)) {
     262           0 :                 DEBUG(0,("become_domain_master_query_fail: Error %d returned when \
     263             : querying WINS server for name %s.\n", 
     264             :                         fail_code, nmb_namestr(question_name)));
     265           0 :                 return;
     266             :         }
     267             : 
     268             :         /* Otherwise - not having the name allows us to register it. */
     269          14 :         pull_ascii_nstring(name, sizeof(name), question_name->name);
     270          14 :         become_domain_master_stage1(subrec, name);
     271             : }
     272             : 
     273             : /****************************************************************************
     274             :   Attempt to become a domain master browser on all broadcast subnets.
     275             :   ****************************************************************************/
     276             : 
     277          62 : static void become_domain_master_browser_bcast(const char *workgroup_name)
     278             : {
     279             :         struct subnet_record *subrec;
     280             : 
     281         124 :         for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { 
     282          62 :                 struct work_record *work = find_workgroup_on_subnet(subrec, workgroup_name);
     283             : 
     284          62 :                 if (work && (work->dom_state == DOMAIN_NONE)) {
     285             :                         struct nmb_name nmbname;
     286          14 :                         make_nmb_name(&nmbname,workgroup_name,0x1b);
     287             : 
     288             :                         /*
     289             :                          * Check for our name on the given broadcast subnet first, only initiate
     290             :                          * further processing if we cannot find it.
     291             :                          */
     292             : 
     293          14 :                         if (find_name_on_subnet(subrec, &nmbname, FIND_SELF_NAME) == NULL) {
     294          14 :                                 if( DEBUGLVL( 0 ) ) {
     295          14 :                                         dbgtext( "become_domain_master_browser_bcast:\n" );
     296          14 :                                         dbgtext( "Attempting to become domain master browser on " );
     297          14 :                                         dbgtext( "workgroup %s on subnet %s\n",
     298             :                                                 workgroup_name, subrec->subnet_name );
     299             :                                 }
     300             : 
     301             :                                 /* Send out a query to establish whether there's a 
     302             :                                    domain controller on the local subnet. If not,
     303             :                                    we can become a domain controller. 
     304             :                                 */
     305             : 
     306          14 :                                 DEBUG(0,("become_domain_master_browser_bcast: querying subnet %s \
     307             : for domain master browser on workgroup %s\n", subrec->subnet_name, workgroup_name));
     308             : 
     309          14 :                                 query_name(subrec, workgroup_name, nmbname.name_type,
     310             :                                         become_domain_master_query_success, 
     311             :                                         become_domain_master_query_fail,
     312             :                                         NULL);
     313             :                         }
     314             :                 }
     315             :         }
     316          62 : }
     317             : 
     318             : /****************************************************************************
     319             :   Attempt to become a domain master browser by registering with WINS.
     320             :   ****************************************************************************/
     321             : 
     322           0 : static void become_domain_master_browser_wins(const char *workgroup_name)
     323             : {
     324             :         struct work_record *work;
     325             : 
     326           0 :         work = find_workgroup_on_subnet(unicast_subnet, workgroup_name);
     327             : 
     328           0 :         if (work && (work->dom_state == DOMAIN_NONE)) {
     329             :                 struct nmb_name nmbname;
     330             : 
     331           0 :                 make_nmb_name(&nmbname,workgroup_name,0x1b);
     332             : 
     333             :                 /*
     334             :                  * Check for our name on the unicast subnet first, only initiate
     335             :                  * further processing if we cannot find it.
     336             :                  */
     337             : 
     338           0 :                 if (find_name_on_subnet(unicast_subnet, &nmbname, FIND_SELF_NAME) == NULL) {
     339           0 :                         if( DEBUGLVL( 0 ) ) {
     340           0 :                                 dbgtext( "become_domain_master_browser_wins:\n" );
     341           0 :                                 dbgtext( "Attempting to become domain master browser " );
     342           0 :                                 dbgtext( "on workgroup %s, subnet %s.\n",
     343           0 :                                         workgroup_name, unicast_subnet->subnet_name );
     344             :                         }
     345             : 
     346             :                         /* Send out a query to establish whether there's a 
     347             :                            domain master browser registered with WINS. If not,
     348             :                            we can become a domain master browser. 
     349             :                         */
     350             : 
     351           0 :                         DEBUG(0,("become_domain_master_browser_wins: querying WINS server from IP %s \
     352             : for domain master browser name %s on workgroup %s\n",
     353             :                                 inet_ntoa(unicast_subnet->myip), nmb_namestr(&nmbname), workgroup_name));
     354             : 
     355           0 :                         query_name(unicast_subnet, workgroup_name, nmbname.name_type,
     356             :                                 become_domain_master_query_success,
     357             :                                 become_domain_master_query_fail,
     358             :                                 NULL);
     359             :                 }
     360             :         }
     361           0 : }
     362             : 
     363             : /****************************************************************************
     364             :   Add the domain logon server and domain master browser names
     365             :   if we are set up to do so.
     366             :   **************************************************************************/
     367             : 
     368       17496 : void add_domain_names(time_t t)
     369             : {
     370             :         static time_t lastrun = 0;
     371             : 
     372       17496 :         if ((lastrun != 0) && (t < lastrun + (CHECK_TIME_ADD_DOM_NAMES * 60)))
     373       17359 :                 return;
     374             : 
     375         137 :         lastrun = t;
     376             : 
     377             :         /* Do the "internet group" - <1c> names. */
     378         137 :         if (IS_DC)
     379          62 :                 add_logon_names();
     380             : 
     381             :         /* Do the domain master names. */
     382         137 :         if(lp_domain_master()) {
     383          62 :                 if(we_are_a_wins_client()) {
     384             :                         /* We register the WORKGROUP<1b> name with the WINS
     385             :                                 server first, and call add_domain_master_bcast()
     386             :                                 only if this is successful.
     387             : 
     388             :                                 This results in domain logon services being gracefully provided,
     389             :                                 as opposed to the aggressive nature of 1.9.16p2 to 1.9.16p11.
     390             :                                 1.9.16p2 to 1.9.16p11 - due to a bug in namelogon.c,
     391             :                                 cannot provide domain master / domain logon services.
     392             :                         */
     393           0 :                         become_domain_master_browser_wins(lp_workgroup());
     394             :                 } else {
     395          62 :                         become_domain_master_browser_bcast(lp_workgroup());
     396             :                 }
     397             :         }
     398             : }

Generated by: LCOV version 1.14