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