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 25extern uint16 samba_nb_type; /* Samba's NetBIOS type. */ 26 27static void become_domain_master_browser_bcast(const char *); 28 29/**************************************************************************** 30 Fail to become a Domain Master Browser on a subnet. 31 ****************************************************************************/ 32 33static void become_domain_master_fail(struct subnet_record *subrec, 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 \ 45workgroup %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 \ 54in 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 \ 66workgroup %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 74static void become_domain_master_stage2(struct subnet_record *subrec, 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 \ 89workgroup %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 \ 95in 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 174static void become_domain_master_stage1(struct subnet_record *subrec, const char *wg_name) 175{ 176 struct work_record *work; 177 178 DEBUG(2,("become_domain_master_stage1: Becoming domain master browser for \ 179workgroup %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 204static void become_domain_master_query_success(struct subnet_record *subrec, 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 250static void become_domain_master_query_fail(struct subnet_record *subrec, 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 \ 261querying 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 275static void become_domain_master_browser_bcast(const char *workgroup_name) 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 \ 305for 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 320static void become_domain_master_browser_wins(const char *workgroup_name) 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 \ 350for 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 366void add_domain_names(time_t t) 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} 397