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 26/* Election parameters. */ 27extern time_t StartupTime; 28 29/**************************************************************************** 30 Send an election datagram packet. 31**************************************************************************/ 32 33static void send_election_dgram(struct subnet_record *subrec, const char *workgroup_name, 34 uint32 criterion, int timeup,const char *server_name) 35{ 36 pstring outbuf; 37 unstring srv_name; 38 char *p; 39 40 DEBUG(2,("send_election_dgram: Sending election packet for workgroup %s on subnet %s\n", 41 workgroup_name, subrec->subnet_name )); 42 43 memset(outbuf,'\0',sizeof(outbuf)); 44 p = outbuf; 45 SCVAL(p,0,ANN_Election); /* Election opcode. */ 46 p++; 47 48 SCVAL(p,0,((criterion == 0 && timeup == 0) ? 0 : ELECTION_VERSION)); 49 SIVAL(p,1,criterion); 50 SIVAL(p,5,timeup*1000); /* ms - Despite what the spec says. */ 51 p += 13; 52 unstrcpy(srv_name, server_name); 53 strupper_m(srv_name); 54 /* The following call does UNIX -> DOS charset conversion. */ 55 pstrcpy_base(p, srv_name, outbuf); 56 p = skip_string(p,1); 57 58 send_mailslot(False, BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf), 59 global_myname(), 0, 60 workgroup_name, 0x1e, 61 subrec->bcast_ip, subrec->myip, DGRAM_PORT); 62} 63 64/******************************************************************* 65 We found a current master browser on one of our broadcast interfaces. 66******************************************************************/ 67 68static void check_for_master_browser_success(struct subnet_record *subrec, 69 struct userdata_struct *userdata, 70 struct nmb_name *answer_name, 71 struct in_addr answer_ip, struct res_rec *rrec) 72{ 73 unstring aname; 74 pull_ascii_nstring(aname, sizeof(aname), answer_name->name); 75 DEBUG(3,("check_for_master_browser_success: Local master browser for workgroup %s exists at \ 76IP %s (just checking).\n", aname, inet_ntoa(answer_ip) )); 77} 78 79/******************************************************************* 80 We failed to find a current master browser on one of our broadcast interfaces. 81******************************************************************/ 82 83static void check_for_master_browser_fail( struct subnet_record *subrec, 84 struct response_record *rrec, 85 struct nmb_name *question_name, 86 int fail_code) 87{ 88 unstring workgroup_name; 89 struct work_record *work; 90 91 pull_ascii_nstring(workgroup_name,sizeof(workgroup_name),question_name->name); 92 93 work = find_workgroup_on_subnet(subrec, workgroup_name); 94 if(work == NULL) { 95 DEBUG(0,("check_for_master_browser_fail: Unable to find workgroup %s on subnet %s.=\n", 96 workgroup_name, subrec->subnet_name )); 97 return; 98 } 99 100 if (strequal(work->work_group, lp_workgroup())) { 101 102 if (lp_local_master()) { 103 /* We have discovered that there is no local master 104 browser, and we are configured to initiate 105 an election that we will participate in. 106 */ 107 DEBUG(2,("check_for_master_browser_fail: Forcing election on workgroup %s subnet %s\n", 108 work->work_group, subrec->subnet_name )); 109 110 /* Setting this means we will participate when the 111 election is run in run_elections(). */ 112 work->needelection = True; 113 } else { 114 /* We need to force an election, because we are configured 115 not to become the local master, but we still need one, 116 having detected that one doesn't exist. 117 */ 118 send_election_dgram(subrec, work->work_group, 0, 0, ""); 119 } 120 } 121} 122 123/******************************************************************* 124 Ensure there is a local master browser for a workgroup on our 125 broadcast interfaces. 126******************************************************************/ 127 128void check_master_browser_exists(time_t t) 129{ 130 static time_t lastrun=0; 131 struct subnet_record *subrec; 132 const char *workgroup_name = lp_workgroup(); 133 134 if (!lastrun) 135 lastrun = t; 136 137 if (t < (lastrun + (CHECK_TIME_MST_BROWSE * 60))) 138 return; 139 140 lastrun = t; 141 142 dump_workgroups(False); 143 144 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { 145 struct work_record *work; 146 147 for (work = subrec->workgrouplist; work; work = work->next) { 148 if (strequal(work->work_group, workgroup_name) && !AM_LOCAL_MASTER_BROWSER(work)) { 149 /* Do a name query for the local master browser on this net. */ 150 query_name( subrec, work->work_group, 0x1d, 151 check_for_master_browser_success, 152 check_for_master_browser_fail, 153 NULL); 154 } 155 } 156 } 157} 158 159/******************************************************************* 160 Run an election. 161******************************************************************/ 162 163void run_elections(time_t t) 164{ 165 static time_t lastime = 0; 166 167 struct subnet_record *subrec; 168 169 /* Send election packets once every 2 seconds - note */ 170 if (lastime && (t - lastime < 2)) 171 return; 172 173 lastime = t; 174 175 START_PROFILE(run_elections); 176 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { 177 struct work_record *work; 178 179 for (work = subrec->workgrouplist; work; work = work->next) { 180 if (work->RunningElection) { 181 /* 182 * We can only run an election for a workgroup if we have 183 * registered the WORKGROUP<1e> name, as that's the name 184 * we must listen to. 185 */ 186 struct nmb_name nmbname; 187 188 make_nmb_name(&nmbname, work->work_group, 0x1e); 189 if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) { 190 DEBUG(8,("run_elections: Cannot send election packet yet as name %s not \ 191yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name )); 192 continue; 193 } 194 195 send_election_dgram(subrec, work->work_group, work->ElectionCriterion, 196 t - StartupTime, global_myname()); 197 198 if (work->ElectionCount++ >= 4) { 199 /* Won election (4 packets were sent out uncontested. */ 200 DEBUG(2,("run_elections: >>> Won election for workgroup %s on subnet %s <<<\n", 201 work->work_group, subrec->subnet_name )); 202 203 work->RunningElection = False; 204 205 become_local_master_browser(subrec, work); 206 } 207 } 208 } 209 } 210 END_PROFILE(run_elections); 211} 212 213/******************************************************************* 214 Determine if I win an election. 215******************************************************************/ 216 217static BOOL win_election(struct work_record *work, int version, 218 uint32 criterion, int timeup, const char *server_name) 219{ 220 int mytimeup = time(NULL) - StartupTime; 221 uint32 mycriterion = work->ElectionCriterion; 222 223 /* If local master is false then never win in election broadcasts. */ 224 if(!lp_local_master()) { 225 DEBUG(3,("win_election: Losing election as local master == False\n")); 226 return False; 227 } 228 229 DEBUG(4,("win_election: election comparison: %x:%x %x:%x %d:%d %s:%s\n", 230 version, ELECTION_VERSION, 231 criterion, mycriterion, 232 timeup, mytimeup, 233 server_name, global_myname())); 234 235 if (version > ELECTION_VERSION) 236 return(False); 237 if (version < ELECTION_VERSION) 238 return(True); 239 240 if (criterion > mycriterion) 241 return(False); 242 if (criterion < mycriterion) 243 return(True); 244 245 if (timeup > mytimeup) 246 return(False); 247 if (timeup < mytimeup) 248 return(True); 249 250 if (StrCaseCmp(global_myname(), server_name) > 0) 251 return(False); 252 253 return(True); 254} 255 256/******************************************************************* 257 Process an incoming election datagram packet. 258******************************************************************/ 259 260void process_election(struct subnet_record *subrec, struct packet_struct *p, char *buf) 261{ 262 struct dgram_packet *dgram = &p->packet.dgram; 263 int version = CVAL(buf,0); 264 uint32 criterion = IVAL(buf,1); 265 int timeup = IVAL(buf,5)/1000; 266 unstring server_name; 267 struct work_record *work; 268 unstring workgroup_name; 269 270 pull_ascii_nstring(server_name, sizeof(server_name), buf+13); 271 pull_ascii_nstring(workgroup_name, sizeof(workgroup_name), dgram->dest_name.name); 272 273 START_PROFILE(election); 274 server_name[15] = 0; 275 276 DEBUG(3,("process_election: Election request from %s at IP %s on subnet %s for workgroup %s.\n", 277 server_name,inet_ntoa(p->ip), subrec->subnet_name, workgroup_name )); 278 279 DEBUG(5,("process_election: vers=%d criterion=%08x timeup=%d\n", version,criterion,timeup)); 280 281 if(( work = find_workgroup_on_subnet(subrec, workgroup_name)) == NULL) { 282 DEBUG(0,("process_election: Cannot find workgroup %s on subnet %s.\n", 283 workgroup_name, subrec->subnet_name )); 284 goto done; 285 } 286 287 if (!strequal(work->work_group, lp_workgroup())) { 288 DEBUG(3,("process_election: ignoring election request for workgroup %s on subnet %s as this \ 289is not my workgroup.\n", work->work_group, subrec->subnet_name )); 290 goto done; 291 } 292 293 if (win_election(work, version,criterion,timeup,server_name)) { 294 /* We take precedence over the requesting server. */ 295 if (!work->RunningElection) { 296 /* We weren't running an election - start running one. */ 297 298 work->needelection = True; 299 work->ElectionCount=0; 300 } 301 302 /* Note that if we were running an election for this workgroup on this 303 subnet already, we just ignore the server we take precedence over. */ 304 } else { 305 /* We lost. Stop participating. */ 306 work->needelection = False; 307 308 if (work->RunningElection || AM_LOCAL_MASTER_BROWSER(work)) { 309 work->RunningElection = False; 310 DEBUG(3,("process_election: >>> Lost election for workgroup %s on subnet %s <<<\n", 311 work->work_group, subrec->subnet_name )); 312 if (AM_LOCAL_MASTER_BROWSER(work)) 313 unbecome_local_master_browser(subrec, work, False); 314 } 315 } 316done: 317 318 END_PROFILE(election); 319} 320 321/**************************************************************************** 322 This function looks over all the workgroups known on all the broadcast 323 subnets and decides if a browser election is to be run on that workgroup. 324 It returns True if any election packets need to be sent (this will then 325 be done by run_elections(). 326***************************************************************************/ 327 328BOOL check_elections(void) 329{ 330 struct subnet_record *subrec; 331 BOOL run_any_election = False; 332 333 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { 334 struct work_record *work; 335 for (work = subrec->workgrouplist; work; work = work->next) { 336 run_any_election |= work->RunningElection; 337 338 /* 339 * Start an election if we have any chance of winning. 340 * Note this is a change to the previous code, that would 341 * only run an election if nmbd was in the potential browser 342 * state. We need to run elections in any state if we're told 343 * to. JRA. 344 */ 345 346 if (work->needelection && !work->RunningElection && lp_local_master()) { 347 /* 348 * We can only run an election for a workgroup if we have 349 * registered the WORKGROUP<1e> name, as that's the name 350 * we must listen to. 351 */ 352 struct nmb_name nmbname; 353 354 make_nmb_name(&nmbname, work->work_group, 0x1e); 355 if(find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME)==NULL) { 356 DEBUG(8,("check_elections: Cannot send election packet yet as name %s not \ 357yet registered on subnet %s\n", nmb_namestr(&nmbname), subrec->subnet_name )); 358 continue; 359 } 360 361 DEBUG(3,("check_elections: >>> Starting election for workgroup %s on subnet %s <<<\n", 362 work->work_group, subrec->subnet_name )); 363 364 work->ElectionCount = 0; 365 work->RunningElection = True; 366 work->needelection = False; 367 } 368 } 369 } 370 return run_any_election; 371} 372 373/**************************************************************************** 374 Process a internal Samba message forcing an election. 375***************************************************************************/ 376 377void nmbd_message_election(int msg_type, pid_t src, void *buf, size_t len) 378{ 379 struct subnet_record *subrec; 380 381 for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) { 382 struct work_record *work; 383 for (work = subrec->workgrouplist; work; work = work->next) { 384 if (strequal(work->work_group, lp_workgroup())) { 385 work->needelection = True; 386 work->ElectionCount=0; 387 work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE; 388 } 389 } 390 } 391} 392