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