root/source3/nmbd/nmbd_become_dmb.c

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

DEFINITIONS

This source file includes following definitions.
  1. become_domain_master_fail
  2. become_domain_master_stage2
  3. become_domain_master_stage1
  4. become_domain_master_query_success
  5. become_domain_master_query_fail
  6. become_domain_master_browser_bcast
  7. become_domain_master_browser_wins
  8. add_domain_names

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

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