| 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 | extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
|
|---|
| 27 |
|
|---|
| 28 | /*******************************************************************
|
|---|
| 29 | Utility function to add a name to the unicast subnet, or add in
|
|---|
| 30 | our IP address if it already exists.
|
|---|
| 31 | ******************************************************************/
|
|---|
| 32 |
|
|---|
| 33 | void insert_permanent_name_into_unicast( struct subnet_record *subrec,
|
|---|
| 34 | struct nmb_name *nmbname, uint16 nb_type )
|
|---|
| 35 | {
|
|---|
| 36 | unstring name;
|
|---|
| 37 | struct name_record *namerec;
|
|---|
| 38 |
|
|---|
| 39 | if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL) {
|
|---|
| 40 | pull_ascii_nstring(name, sizeof(name), nmbname->name);
|
|---|
| 41 | /* The name needs to be created on the unicast subnet. */
|
|---|
| 42 | (void)add_name_to_subnet( unicast_subnet, name,
|
|---|
| 43 | nmbname->name_type, nb_type,
|
|---|
| 44 | PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
|
|---|
| 45 | } else {
|
|---|
| 46 | /* The name already exists on the unicast subnet. Add our local
|
|---|
| 47 | IP for the given broadcast subnet to the name. */
|
|---|
| 48 | add_ip_to_name_record( namerec, subrec->myip);
|
|---|
| 49 | }
|
|---|
| 50 | }
|
|---|
| 51 |
|
|---|
| 52 | /*******************************************************************
|
|---|
| 53 | Utility function to remove a name from the unicast subnet.
|
|---|
| 54 | ******************************************************************/
|
|---|
| 55 |
|
|---|
| 56 | static void remove_permanent_name_from_unicast( struct subnet_record *subrec,
|
|---|
| 57 | struct nmb_name *nmbname )
|
|---|
| 58 | {
|
|---|
| 59 | struct name_record *namerec;
|
|---|
| 60 |
|
|---|
| 61 | if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) != NULL) {
|
|---|
| 62 | /* Remove this broadcast subnet IP address from the name. */
|
|---|
| 63 | remove_ip_from_name_record( namerec, subrec->myip);
|
|---|
| 64 | if(namerec->data.num_ips == 0)
|
|---|
| 65 | remove_name_from_namelist( unicast_subnet, namerec);
|
|---|
| 66 | }
|
|---|
| 67 | }
|
|---|
| 68 |
|
|---|
| 69 | /*******************************************************************
|
|---|
| 70 | Utility function always called to set our workgroup and server
|
|---|
| 71 | state back to potential browser, or none.
|
|---|
| 72 | ******************************************************************/
|
|---|
| 73 |
|
|---|
| 74 | static void reset_workgroup_state( struct subnet_record *subrec, const char *workgroup_name,
|
|---|
| 75 | BOOL force_new_election )
|
|---|
| 76 | {
|
|---|
| 77 | struct work_record *work;
|
|---|
| 78 | struct server_record *servrec;
|
|---|
| 79 | struct nmb_name nmbname;
|
|---|
| 80 |
|
|---|
| 81 | if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL) {
|
|---|
| 82 | DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
|
|---|
| 83 | subnet %s.\n", workgroup_name, subrec->subnet_name ));
|
|---|
| 84 | return;
|
|---|
| 85 | }
|
|---|
| 86 |
|
|---|
| 87 | if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
|
|---|
| 88 | DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
|
|---|
| 89 | in workgroup %s on subnet %s\n",
|
|---|
| 90 | global_myname(), work->work_group, subrec->subnet_name));
|
|---|
| 91 | work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
|
|---|
| 92 | return;
|
|---|
| 93 | }
|
|---|
| 94 |
|
|---|
| 95 | /* Update our server status - remove any master flag and replace
|
|---|
| 96 | it with the potential browser flag. */
|
|---|
| 97 | servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
|
|---|
| 98 | servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
|
|---|
| 99 |
|
|---|
| 100 | /* Tell the namelist writer to write out a change. */
|
|---|
| 101 | subrec->work_changed = True;
|
|---|
| 102 |
|
|---|
| 103 | /* Reset our election flags. */
|
|---|
| 104 | work->ElectionCriterion &= ~0x4;
|
|---|
| 105 |
|
|---|
| 106 | work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
|
|---|
| 107 |
|
|---|
| 108 | /* Forget who the local master browser was for
|
|---|
| 109 | this workgroup. */
|
|---|
| 110 |
|
|---|
| 111 | set_workgroup_local_master_browser_name( work, "");
|
|---|
| 112 |
|
|---|
| 113 | /*
|
|---|
| 114 | * Ensure the IP address of this subnet is not registered as one
|
|---|
| 115 | * of the IP addresses of the WORKGROUP<1d> name on the unicast
|
|---|
| 116 | * subnet. This undoes what we did below when we became a local
|
|---|
| 117 | * master browser.
|
|---|
| 118 | */
|
|---|
| 119 |
|
|---|
| 120 | make_nmb_name(&nmbname, work->work_group, 0x1d);
|
|---|
| 121 |
|
|---|
| 122 | remove_permanent_name_from_unicast( subrec, &nmbname);
|
|---|
| 123 |
|
|---|
| 124 | if(force_new_election)
|
|---|
| 125 | work->needelection = True;
|
|---|
| 126 | }
|
|---|
| 127 |
|
|---|
| 128 | /*******************************************************************
|
|---|
| 129 | Unbecome the local master browser name release success function.
|
|---|
| 130 | ******************************************************************/
|
|---|
| 131 |
|
|---|
| 132 | static void unbecome_local_master_success(struct subnet_record *subrec,
|
|---|
| 133 | struct userdata_struct *userdata,
|
|---|
| 134 | struct nmb_name *released_name,
|
|---|
| 135 | struct in_addr released_ip)
|
|---|
| 136 | {
|
|---|
| 137 | BOOL force_new_election = False;
|
|---|
| 138 | unstring relname;
|
|---|
| 139 |
|
|---|
| 140 | memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
|
|---|
| 141 |
|
|---|
| 142 | DEBUG(3,("unbecome_local_master_success: released name %s.\n",
|
|---|
| 143 | nmb_namestr(released_name)));
|
|---|
| 144 |
|
|---|
| 145 | /* Now reset the workgroup and server state. */
|
|---|
| 146 | pull_ascii_nstring(relname, sizeof(relname), released_name->name);
|
|---|
| 147 | reset_workgroup_state( subrec, relname, force_new_election );
|
|---|
| 148 |
|
|---|
| 149 | if( DEBUGLVL( 0 ) ) {
|
|---|
| 150 | dbgtext( "*****\n\n" );
|
|---|
| 151 | dbgtext( "Samba name server %s ", global_myname() );
|
|---|
| 152 | dbgtext( "has stopped being a local master browser " );
|
|---|
| 153 | dbgtext( "for workgroup %s ", relname );
|
|---|
| 154 | dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
|
|---|
| 155 | }
|
|---|
| 156 |
|
|---|
| 157 | }
|
|---|
| 158 |
|
|---|
| 159 | /*******************************************************************
|
|---|
| 160 | Unbecome the local master browser name release fail function.
|
|---|
| 161 | ******************************************************************/
|
|---|
| 162 |
|
|---|
| 163 | static void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec,
|
|---|
| 164 | struct nmb_name *fail_name)
|
|---|
| 165 | {
|
|---|
| 166 | struct name_record *namerec;
|
|---|
| 167 | struct userdata_struct *userdata = rrec->userdata;
|
|---|
| 168 | BOOL force_new_election = False;
|
|---|
| 169 | unstring failname;
|
|---|
| 170 |
|
|---|
| 171 | memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
|
|---|
| 172 |
|
|---|
| 173 | DEBUG(0,("unbecome_local_master_fail: failed to release name %s. \
|
|---|
| 174 | Removing from namelist anyway.\n", nmb_namestr(fail_name)));
|
|---|
| 175 |
|
|---|
| 176 | /* Do it anyway. */
|
|---|
| 177 | namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
|
|---|
| 178 | if(namerec)
|
|---|
| 179 | remove_name_from_namelist(subrec, namerec);
|
|---|
| 180 |
|
|---|
| 181 | /* Now reset the workgroup and server state. */
|
|---|
| 182 | pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
|
|---|
| 183 | reset_workgroup_state( subrec, failname, force_new_election );
|
|---|
| 184 |
|
|---|
| 185 | if( DEBUGLVL( 0 ) ) {
|
|---|
| 186 | dbgtext( "*****\n\n" );
|
|---|
| 187 | dbgtext( "Samba name server %s ", global_myname() );
|
|---|
| 188 | dbgtext( "has stopped being a local master browser " );
|
|---|
| 189 | dbgtext( "for workgroup %s ", failname );
|
|---|
| 190 | dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
|
|---|
| 191 | }
|
|---|
| 192 | }
|
|---|
| 193 |
|
|---|
| 194 | /*******************************************************************
|
|---|
| 195 | Utility function to remove the WORKGROUP<1d> name.
|
|---|
| 196 | ******************************************************************/
|
|---|
| 197 |
|
|---|
| 198 | static void release_1d_name( struct subnet_record *subrec, const char *workgroup_name,
|
|---|
| 199 | BOOL force_new_election)
|
|---|
| 200 | {
|
|---|
| 201 | struct nmb_name nmbname;
|
|---|
| 202 | struct name_record *namerec;
|
|---|
| 203 |
|
|---|
| 204 | make_nmb_name(&nmbname, workgroup_name, 0x1d);
|
|---|
| 205 | if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) {
|
|---|
| 206 | struct userdata_struct *userdata;
|
|---|
| 207 | size_t size = sizeof(struct userdata_struct) + sizeof(BOOL);
|
|---|
| 208 |
|
|---|
| 209 | if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {
|
|---|
| 210 | DEBUG(0,("release_1d_name: malloc fail.\n"));
|
|---|
| 211 | return;
|
|---|
| 212 | }
|
|---|
| 213 |
|
|---|
| 214 | userdata->copy_fn = NULL;
|
|---|
| 215 | userdata->free_fn = NULL;
|
|---|
| 216 | userdata->userdata_len = sizeof(BOOL);
|
|---|
| 217 | memcpy((char *)userdata->data, &force_new_election, sizeof(BOOL));
|
|---|
| 218 |
|
|---|
| 219 | release_name(subrec, namerec,
|
|---|
| 220 | unbecome_local_master_success,
|
|---|
| 221 | unbecome_local_master_fail,
|
|---|
| 222 | userdata);
|
|---|
| 223 |
|
|---|
| 224 | zero_free(userdata, size);
|
|---|
| 225 | }
|
|---|
| 226 | }
|
|---|
| 227 |
|
|---|
| 228 | /*******************************************************************
|
|---|
| 229 | Unbecome the local master browser MSBROWSE name release success function.
|
|---|
| 230 | ******************************************************************/
|
|---|
| 231 |
|
|---|
| 232 | static void release_msbrowse_name_success(struct subnet_record *subrec,
|
|---|
| 233 | struct userdata_struct *userdata,
|
|---|
| 234 | struct nmb_name *released_name,
|
|---|
| 235 | struct in_addr released_ip)
|
|---|
| 236 | {
|
|---|
| 237 | DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
|
|---|
| 238 | nmb_namestr(released_name), subrec->subnet_name ));
|
|---|
| 239 |
|
|---|
| 240 | /* Remove the permanent MSBROWSE name added into the unicast subnet. */
|
|---|
| 241 | remove_permanent_name_from_unicast( subrec, released_name);
|
|---|
| 242 | }
|
|---|
| 243 |
|
|---|
| 244 | /*******************************************************************
|
|---|
| 245 | Unbecome the local master browser MSBROWSE name release fail function.
|
|---|
| 246 | ******************************************************************/
|
|---|
| 247 |
|
|---|
| 248 | static void release_msbrowse_name_fail( struct subnet_record *subrec,
|
|---|
| 249 | struct response_record *rrec,
|
|---|
| 250 | struct nmb_name *fail_name)
|
|---|
| 251 | {
|
|---|
| 252 | struct name_record *namerec;
|
|---|
| 253 |
|
|---|
| 254 | DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
|
|---|
| 255 | nmb_namestr(fail_name), subrec->subnet_name ));
|
|---|
| 256 |
|
|---|
| 257 | /* Release the name anyway. */
|
|---|
| 258 | namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
|
|---|
| 259 | if(namerec)
|
|---|
| 260 | remove_name_from_namelist(subrec, namerec);
|
|---|
| 261 |
|
|---|
| 262 | /* Remove the permanent MSBROWSE name added into the unicast subnet. */
|
|---|
| 263 | remove_permanent_name_from_unicast( subrec, fail_name);
|
|---|
| 264 | }
|
|---|
| 265 |
|
|---|
| 266 | /*******************************************************************
|
|---|
| 267 | Unbecome the local master browser. If force_new_election is true, restart
|
|---|
| 268 | the election process after we've unbecome the local master.
|
|---|
| 269 | ******************************************************************/
|
|---|
| 270 |
|
|---|
| 271 | void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work,
|
|---|
| 272 | BOOL force_new_election)
|
|---|
| 273 | {
|
|---|
| 274 | struct name_record *namerec;
|
|---|
| 275 | struct nmb_name nmbname;
|
|---|
| 276 |
|
|---|
| 277 | /* Sanity check. */
|
|---|
| 278 |
|
|---|
| 279 | DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \
|
|---|
| 280 | on subnet %s\n",work->work_group, subrec->subnet_name));
|
|---|
| 281 |
|
|---|
| 282 | if(find_server_in_workgroup( work, global_myname()) == NULL) {
|
|---|
| 283 | DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
|
|---|
| 284 | in workgroup %s on subnet %s\n",
|
|---|
| 285 | global_myname(), work->work_group, subrec->subnet_name));
|
|---|
| 286 | work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
|
|---|
| 287 | return;
|
|---|
| 288 | }
|
|---|
| 289 |
|
|---|
| 290 | /* Set the state to unbecoming. */
|
|---|
| 291 | work->mst_state = MST_UNBECOMING_MASTER;
|
|---|
| 292 |
|
|---|
| 293 | /*
|
|---|
| 294 | * Release the WORKGROUP<1d> name asap to allow another machine to
|
|---|
| 295 | * claim it.
|
|---|
| 296 | */
|
|---|
| 297 |
|
|---|
| 298 | release_1d_name( subrec, work->work_group, force_new_election);
|
|---|
| 299 |
|
|---|
| 300 | /* Deregister any browser names we may have. */
|
|---|
| 301 | make_nmb_name(&nmbname, MSBROWSE, 0x1);
|
|---|
| 302 | if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) {
|
|---|
| 303 | release_name(subrec, namerec,
|
|---|
| 304 | release_msbrowse_name_success,
|
|---|
| 305 | release_msbrowse_name_fail,
|
|---|
| 306 | NULL);
|
|---|
| 307 | }
|
|---|
| 308 |
|
|---|
| 309 | /*
|
|---|
| 310 | * Ensure we have sent and processed these release packets
|
|---|
| 311 | * before returning - we don't want to process any election
|
|---|
| 312 | * packets before dealing with the 1d release.
|
|---|
| 313 | */
|
|---|
| 314 |
|
|---|
| 315 | retransmit_or_expire_response_records(time(NULL));
|
|---|
| 316 | }
|
|---|
| 317 |
|
|---|
| 318 | /****************************************************************************
|
|---|
| 319 | Success in registering the WORKGROUP<1d> name.
|
|---|
| 320 | We are now *really* a local master browser.
|
|---|
| 321 | ****************************************************************************/
|
|---|
| 322 |
|
|---|
| 323 | static void become_local_master_stage2(struct subnet_record *subrec,
|
|---|
| 324 | struct userdata_struct *userdata,
|
|---|
| 325 | struct nmb_name *registered_name,
|
|---|
| 326 | uint16 nb_flags,
|
|---|
| 327 | int ttl, struct in_addr registered_ip)
|
|---|
| 328 | {
|
|---|
| 329 | int i = 0;
|
|---|
| 330 | struct server_record *sl;
|
|---|
| 331 | struct work_record *work;
|
|---|
| 332 | struct server_record *servrec;
|
|---|
| 333 | unstring regname;
|
|---|
| 334 |
|
|---|
| 335 | pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
|
|---|
| 336 | work = find_workgroup_on_subnet( subrec, regname);
|
|---|
| 337 |
|
|---|
| 338 | if(!work) {
|
|---|
| 339 | DEBUG(0,("become_local_master_stage2: Error - cannot find \
|
|---|
| 340 | workgroup %s on subnet %s\n", regname, subrec->subnet_name));
|
|---|
| 341 | return;
|
|---|
| 342 | }
|
|---|
| 343 |
|
|---|
| 344 | if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
|
|---|
| 345 | DEBUG(0,("become_local_master_stage2: Error - cannot find server %s \
|
|---|
| 346 | in workgroup %s on subnet %s\n",
|
|---|
| 347 | global_myname(), regname, subrec->subnet_name));
|
|---|
| 348 | work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
|
|---|
| 349 | return;
|
|---|
| 350 | }
|
|---|
| 351 |
|
|---|
| 352 | DEBUG(3,("become_local_master_stage2: registered as master browser for workgroup %s \
|
|---|
| 353 | on subnet %s\n", work->work_group, subrec->subnet_name));
|
|---|
| 354 |
|
|---|
| 355 | work->mst_state = MST_BROWSER; /* registering WORKGROUP(1d) succeeded */
|
|---|
| 356 |
|
|---|
| 357 | /* update our server status */
|
|---|
| 358 | servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
|
|---|
| 359 | servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
|
|---|
| 360 |
|
|---|
| 361 | /* Tell the namelist writer to write out a change. */
|
|---|
| 362 | subrec->work_changed = True;
|
|---|
| 363 |
|
|---|
| 364 | /* Add this name to the workgroup as local master browser. */
|
|---|
| 365 | set_workgroup_local_master_browser_name( work, global_myname());
|
|---|
| 366 |
|
|---|
| 367 | /* Count the number of servers we have on our list. If it's
|
|---|
| 368 | less than 10 (just a heuristic) request the servers
|
|---|
| 369 | to announce themselves.
|
|---|
| 370 | */
|
|---|
| 371 | for( sl = work->serverlist; sl != NULL; sl = sl->next)
|
|---|
| 372 | i++;
|
|---|
| 373 |
|
|---|
| 374 | if (i < 10) {
|
|---|
| 375 | /* Ask all servers on our local net to announce to us. */
|
|---|
| 376 | broadcast_announce_request(subrec, work);
|
|---|
| 377 | }
|
|---|
| 378 |
|
|---|
| 379 | /*
|
|---|
| 380 | * Now we are a local master on a broadcast subnet, we need to add
|
|---|
| 381 | * the WORKGROUP<1d> name to the unicast subnet so that we can answer
|
|---|
| 382 | * unicast requests sent to this name. We can create this name directly on
|
|---|
| 383 | * the unicast subnet as a WINS server always returns true when registering
|
|---|
| 384 | * this name, and discards the registration. We use the number of IP
|
|---|
| 385 | * addresses registered to this name as a reference count, as we
|
|---|
| 386 | * remove this broadcast subnet IP address from it when we stop becoming a local
|
|---|
| 387 | * master browser for this broadcast subnet.
|
|---|
| 388 | */
|
|---|
| 389 |
|
|---|
| 390 | insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
|
|---|
| 391 |
|
|---|
| 392 | /* Reset the announce master browser timer so that we try and tell a domain
|
|---|
| 393 | master browser as soon as possible that we are a local master browser. */
|
|---|
| 394 | reset_announce_timer();
|
|---|
| 395 |
|
|---|
| 396 | if( DEBUGLVL( 0 ) ) {
|
|---|
| 397 | dbgtext( "*****\n\n" );
|
|---|
| 398 | dbgtext( "Samba name server %s ", global_myname() );
|
|---|
| 399 | dbgtext( "is now a local master browser " );
|
|---|
| 400 | dbgtext( "for workgroup %s ", work->work_group );
|
|---|
| 401 | dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
|
|---|
| 402 | }
|
|---|
| 403 | }
|
|---|
| 404 |
|
|---|
| 405 | /****************************************************************************
|
|---|
| 406 | Failed to register the WORKGROUP<1d> name.
|
|---|
| 407 | ****************************************************************************/
|
|---|
| 408 |
|
|---|
| 409 | static void become_local_master_fail2(struct subnet_record *subrec,
|
|---|
| 410 | struct response_record *rrec,
|
|---|
| 411 | struct nmb_name *fail_name)
|
|---|
| 412 | {
|
|---|
| 413 | unstring failname;
|
|---|
| 414 | struct work_record *work;
|
|---|
| 415 |
|
|---|
| 416 | DEBUG(0,("become_local_master_fail2: failed to register name %s on subnet %s. \
|
|---|
| 417 | Failed to become a local master browser.\n", nmb_namestr(fail_name), subrec->subnet_name));
|
|---|
| 418 |
|
|---|
| 419 | pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
|
|---|
| 420 | work = find_workgroup_on_subnet( subrec, failname);
|
|---|
| 421 |
|
|---|
| 422 | if(!work) {
|
|---|
| 423 | DEBUG(0,("become_local_master_fail2: Error - cannot find \
|
|---|
| 424 | workgroup %s on subnet %s\n", failname, subrec->subnet_name));
|
|---|
| 425 | return;
|
|---|
| 426 | }
|
|---|
| 427 |
|
|---|
| 428 | /* Roll back all the way by calling unbecome_local_master_browser(). */
|
|---|
| 429 | unbecome_local_master_browser(subrec, work, False);
|
|---|
| 430 | }
|
|---|
| 431 |
|
|---|
| 432 | /****************************************************************************
|
|---|
| 433 | Success in registering the MSBROWSE name.
|
|---|
| 434 | ****************************************************************************/
|
|---|
| 435 |
|
|---|
| 436 | static void become_local_master_stage1(struct subnet_record *subrec,
|
|---|
| 437 | struct userdata_struct *userdata,
|
|---|
| 438 | struct nmb_name *registered_name,
|
|---|
| 439 | uint16 nb_flags,
|
|---|
| 440 | int ttl, struct in_addr registered_ip)
|
|---|
| 441 | {
|
|---|
| 442 | char *work_name = userdata->data;
|
|---|
| 443 | struct work_record *work = find_workgroup_on_subnet( subrec, work_name);
|
|---|
| 444 |
|
|---|
| 445 | if(!work) {
|
|---|
| 446 | DEBUG(0,("become_local_master_stage1: Error - cannot find \
|
|---|
| 447 | %s on subnet %s\n", work_name, subrec->subnet_name));
|
|---|
| 448 | return;
|
|---|
| 449 | }
|
|---|
| 450 |
|
|---|
| 451 | DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n",
|
|---|
| 452 | work->work_group));
|
|---|
| 453 |
|
|---|
| 454 | work->mst_state = MST_MSB; /* Registering MSBROWSE was successful. */
|
|---|
| 455 |
|
|---|
| 456 | /*
|
|---|
| 457 | * We registered the MSBROWSE name on a broadcast subnet, now need to add
|
|---|
| 458 | * the MSBROWSE name to the unicast subnet so that we can answer
|
|---|
| 459 | * unicast requests sent to this name. We create this name directly on
|
|---|
| 460 | * the unicast subnet.
|
|---|
| 461 | */
|
|---|
| 462 |
|
|---|
| 463 | insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
|
|---|
| 464 |
|
|---|
| 465 | /* Attempt to register the WORKGROUP<1d> name. */
|
|---|
| 466 | register_name(subrec, work->work_group,0x1d,samba_nb_type,
|
|---|
| 467 | become_local_master_stage2,
|
|---|
| 468 | become_local_master_fail2,
|
|---|
| 469 | NULL);
|
|---|
| 470 | }
|
|---|
| 471 |
|
|---|
| 472 | /****************************************************************************
|
|---|
| 473 | Failed to register the MSBROWSE name.
|
|---|
| 474 | ****************************************************************************/
|
|---|
| 475 |
|
|---|
| 476 | static void become_local_master_fail1(struct subnet_record *subrec,
|
|---|
| 477 | struct response_record *rrec,
|
|---|
| 478 | struct nmb_name *fail_name)
|
|---|
| 479 | {
|
|---|
| 480 | char *work_name = rrec->userdata->data;
|
|---|
| 481 | struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
|
|---|
| 482 |
|
|---|
| 483 | if(!work) {
|
|---|
| 484 | DEBUG(0,("become_local_master_fail1: Error - cannot find \
|
|---|
| 485 | workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
|
|---|
| 486 | return;
|
|---|
| 487 | }
|
|---|
| 488 |
|
|---|
| 489 | if(find_server_in_workgroup(work, global_myname()) == NULL) {
|
|---|
| 490 | DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
|
|---|
| 491 | in workgroup %s on subnet %s\n",
|
|---|
| 492 | global_myname(), work->work_group, subrec->subnet_name));
|
|---|
| 493 | return;
|
|---|
| 494 | }
|
|---|
| 495 |
|
|---|
| 496 | reset_workgroup_state( subrec, work->work_group, False );
|
|---|
| 497 |
|
|---|
| 498 | DEBUG(0,("become_local_master_fail1: Failed to become a local master browser for \
|
|---|
| 499 | workgroup %s on subnet %s. Couldn't register name %s.\n",
|
|---|
| 500 | work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
|
|---|
| 501 | }
|
|---|
| 502 |
|
|---|
| 503 | /******************************************************************
|
|---|
| 504 | Become the local master browser on a subnet.
|
|---|
| 505 | This gets called if we win an election on this subnet.
|
|---|
| 506 |
|
|---|
| 507 | Stage 1: mst_state was MST_POTENTIAL - go to MST_BACK register ^1^2__MSBROWSE__^2^1.
|
|---|
| 508 | Stage 2: mst_state was MST_BACKUP - go to MST_MSB and register WORKGROUP<1d>.
|
|---|
| 509 | Stage 3: mst_state was MST_MSB - go to MST_BROWSER.
|
|---|
| 510 | ******************************************************************/
|
|---|
| 511 |
|
|---|
| 512 | void become_local_master_browser(struct subnet_record *subrec, struct work_record *work)
|
|---|
| 513 | {
|
|---|
| 514 | struct userdata_struct *userdata;
|
|---|
| 515 | size_t size = sizeof(struct userdata_struct) + sizeof(fstring) + 1;
|
|---|
| 516 |
|
|---|
| 517 | /* Sanity check. */
|
|---|
| 518 | if (!lp_local_master()) {
|
|---|
| 519 | DEBUG(0,("become_local_master_browser: Samba not configured as a local master browser.\n"));
|
|---|
| 520 | return;
|
|---|
| 521 | }
|
|---|
| 522 |
|
|---|
| 523 | if(!AM_POTENTIAL_MASTER_BROWSER(work)) {
|
|---|
| 524 | DEBUG(2,("become_local_master_browser: Awaiting potential browser state. Current state is %d\n",
|
|---|
| 525 | work->mst_state ));
|
|---|
| 526 | return;
|
|---|
| 527 | }
|
|---|
| 528 |
|
|---|
| 529 | if(find_server_in_workgroup( work, global_myname()) == NULL) {
|
|---|
| 530 | DEBUG(0,("become_local_master_browser: Error - cannot find server %s \
|
|---|
| 531 | in workgroup %s on subnet %s\n",
|
|---|
| 532 | global_myname(), work->work_group, subrec->subnet_name));
|
|---|
| 533 | return;
|
|---|
| 534 | }
|
|---|
| 535 |
|
|---|
| 536 | DEBUG(2,("become_local_master_browser: Starting to become a master browser for workgroup \
|
|---|
| 537 | %s on subnet %s\n", work->work_group, subrec->subnet_name));
|
|---|
| 538 |
|
|---|
| 539 | DEBUG(3,("become_local_master_browser: first stage - attempt to register ^1^2__MSBROWSE__^2^1\n"));
|
|---|
| 540 | work->mst_state = MST_BACKUP; /* an election win was successful */
|
|---|
| 541 |
|
|---|
| 542 | work->ElectionCriterion |= 0x5;
|
|---|
| 543 |
|
|---|
| 544 | /* Tell the namelist writer to write out a change. */
|
|---|
| 545 | subrec->work_changed = True;
|
|---|
| 546 |
|
|---|
| 547 | /* Setup the userdata_struct. */
|
|---|
| 548 | if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {
|
|---|
| 549 | DEBUG(0,("become_local_master_browser: malloc fail.\n"));
|
|---|
| 550 | return;
|
|---|
| 551 | }
|
|---|
| 552 |
|
|---|
| 553 | userdata->copy_fn = NULL;
|
|---|
| 554 | userdata->free_fn = NULL;
|
|---|
| 555 | userdata->userdata_len = strlen(work->work_group)+1;
|
|---|
| 556 | overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
|
|---|
| 557 |
|
|---|
| 558 | /* Register the special browser group name. */
|
|---|
| 559 | register_name(subrec, MSBROWSE, 0x01, samba_nb_type|NB_GROUP,
|
|---|
| 560 | become_local_master_stage1,
|
|---|
| 561 | become_local_master_fail1,
|
|---|
| 562 | userdata);
|
|---|
| 563 |
|
|---|
| 564 | zero_free(userdata, size);
|
|---|
| 565 | }
|
|---|
| 566 |
|
|---|
| 567 | /***************************************************************
|
|---|
| 568 | Utility function to set the local master browser name. Does
|
|---|
| 569 | some sanity checking as old versions of Samba seem to sometimes
|
|---|
| 570 | say that the master browser name for a workgroup is the same
|
|---|
| 571 | as the workgroup name.
|
|---|
| 572 | ****************************************************************/
|
|---|
| 573 |
|
|---|
| 574 | void set_workgroup_local_master_browser_name( struct work_record *work, const char *newname)
|
|---|
| 575 | {
|
|---|
| 576 | DEBUG(5,("set_workgroup_local_master_browser_name: setting local master name to '%s' \
|
|---|
| 577 | for workgroup %s.\n", newname, work->work_group ));
|
|---|
| 578 |
|
|---|
| 579 | #if 0
|
|---|
| 580 | /*
|
|---|
| 581 | * Apparently some sites use the workgroup name as the local
|
|---|
| 582 | * master browser name. Arrrrggghhhhh ! (JRA).
|
|---|
| 583 | */
|
|---|
| 584 | if(strequal( work->work_group, newname))
|
|---|
| 585 | {
|
|---|
| 586 | DEBUG(5, ("set_workgroup_local_master_browser_name: Refusing to set \
|
|---|
| 587 | local_master_browser_name for workgroup %s to workgroup name.\n",
|
|---|
| 588 | work->work_group ));
|
|---|
| 589 | return;
|
|---|
| 590 | }
|
|---|
| 591 | #endif
|
|---|
| 592 |
|
|---|
| 593 | unstrcpy(work->local_master_browser_name, newname);
|
|---|
| 594 | }
|
|---|