00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "includes.h"
00025
00026 extern uint16 samba_nb_type;
00027
00028
00029
00030
00031
00032
00033 void insert_permanent_name_into_unicast( struct subnet_record *subrec,
00034 struct nmb_name *nmbname, uint16 nb_type )
00035 {
00036 unstring name;
00037 struct name_record *namerec;
00038
00039 if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) == NULL) {
00040 pull_ascii_nstring(name, sizeof(name), nmbname->name);
00041
00042 (void)add_name_to_subnet( unicast_subnet, name,
00043 nmbname->name_type, nb_type,
00044 PERMANENT_TTL, PERMANENT_NAME, 1, &subrec->myip);
00045 } else {
00046
00047
00048 add_ip_to_name_record( namerec, subrec->myip);
00049 }
00050 }
00051
00052
00053
00054
00055
00056 static void remove_permanent_name_from_unicast( struct subnet_record *subrec,
00057 struct nmb_name *nmbname )
00058 {
00059 struct name_record *namerec;
00060
00061 if((namerec = find_name_on_subnet(unicast_subnet, nmbname, FIND_SELF_NAME)) != NULL) {
00062
00063 remove_ip_from_name_record( namerec, subrec->myip);
00064 if(namerec->data.num_ips == 0)
00065 remove_name_from_namelist( unicast_subnet, namerec);
00066 }
00067 }
00068
00069
00070
00071
00072
00073
00074 static void reset_workgroup_state( struct subnet_record *subrec, const char *workgroup_name,
00075 BOOL force_new_election )
00076 {
00077 struct work_record *work;
00078 struct server_record *servrec;
00079 struct nmb_name nmbname;
00080
00081 if((work = find_workgroup_on_subnet( subrec, workgroup_name)) == NULL) {
00082 DEBUG(0,("reset_workgroup_state: Error - cannot find workgroup %s on \
00083 subnet %s.\n", workgroup_name, subrec->subnet_name ));
00084 return;
00085 }
00086
00087 if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
00088 DEBUG(0,("reset_workgroup_state: Error - cannot find server %s \
00089 in workgroup %s on subnet %s\n",
00090 global_myname(), work->work_group, subrec->subnet_name));
00091 work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
00092 return;
00093 }
00094
00095
00096
00097 servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
00098 servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
00099
00100
00101 subrec->work_changed = True;
00102
00103
00104 work->ElectionCriterion &= ~0x4;
00105
00106 work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
00107
00108
00109
00110
00111 set_workgroup_local_master_browser_name( work, "");
00112
00113
00114
00115
00116
00117
00118
00119
00120 make_nmb_name(&nmbname, work->work_group, 0x1d);
00121
00122 remove_permanent_name_from_unicast( subrec, &nmbname);
00123
00124 if(force_new_election)
00125 work->needelection = True;
00126 }
00127
00128
00129
00130
00131
00132 static void unbecome_local_master_success(struct subnet_record *subrec,
00133 struct userdata_struct *userdata,
00134 struct nmb_name *released_name,
00135 struct in_addr released_ip)
00136 {
00137 BOOL force_new_election = False;
00138 unstring relname;
00139
00140 memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
00141
00142 DEBUG(3,("unbecome_local_master_success: released name %s.\n",
00143 nmb_namestr(released_name)));
00144
00145
00146 pull_ascii_nstring(relname, sizeof(relname), released_name->name);
00147 reset_workgroup_state( subrec, relname, force_new_election );
00148
00149 if( DEBUGLVL( 0 ) ) {
00150 dbgtext( "*****\n\n" );
00151 dbgtext( "Samba name server %s ", global_myname() );
00152 dbgtext( "has stopped being a local master browser " );
00153 dbgtext( "for workgroup %s ", relname );
00154 dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
00155 }
00156
00157 }
00158
00159
00160
00161
00162
00163 static void unbecome_local_master_fail(struct subnet_record *subrec, struct response_record *rrec,
00164 struct nmb_name *fail_name)
00165 {
00166 struct name_record *namerec;
00167 struct userdata_struct *userdata = rrec->userdata;
00168 BOOL force_new_election = False;
00169 unstring failname;
00170
00171 memcpy((char *)&force_new_election, userdata->data, sizeof(BOOL));
00172
00173 DEBUG(0,("unbecome_local_master_fail: failed to release name %s. \
00174 Removing from namelist anyway.\n", nmb_namestr(fail_name)));
00175
00176
00177 namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
00178 if(namerec)
00179 remove_name_from_namelist(subrec, namerec);
00180
00181
00182 pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
00183 reset_workgroup_state( subrec, failname, force_new_election );
00184
00185 if( DEBUGLVL( 0 ) ) {
00186 dbgtext( "*****\n\n" );
00187 dbgtext( "Samba name server %s ", global_myname() );
00188 dbgtext( "has stopped being a local master browser " );
00189 dbgtext( "for workgroup %s ", failname );
00190 dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
00191 }
00192 }
00193
00194
00195
00196
00197
00198 static void release_1d_name( struct subnet_record *subrec, const char *workgroup_name,
00199 BOOL force_new_election)
00200 {
00201 struct nmb_name nmbname;
00202 struct name_record *namerec;
00203
00204 make_nmb_name(&nmbname, workgroup_name, 0x1d);
00205 if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) {
00206 struct userdata_struct *userdata;
00207 size_t size = sizeof(struct userdata_struct) + sizeof(BOOL);
00208
00209 if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {
00210 DEBUG(0,("release_1d_name: malloc fail.\n"));
00211 return;
00212 }
00213
00214 userdata->copy_fn = NULL;
00215 userdata->free_fn = NULL;
00216 userdata->userdata_len = sizeof(BOOL);
00217 memcpy((char *)userdata->data, &force_new_election, sizeof(BOOL));
00218
00219 release_name(subrec, namerec,
00220 unbecome_local_master_success,
00221 unbecome_local_master_fail,
00222 userdata);
00223
00224 zero_free(userdata, size);
00225 }
00226 }
00227
00228
00229
00230
00231
00232 static void release_msbrowse_name_success(struct subnet_record *subrec,
00233 struct userdata_struct *userdata,
00234 struct nmb_name *released_name,
00235 struct in_addr released_ip)
00236 {
00237 DEBUG(4,("release_msbrowse_name_success: Released name %s on subnet %s\n.",
00238 nmb_namestr(released_name), subrec->subnet_name ));
00239
00240
00241 remove_permanent_name_from_unicast( subrec, released_name);
00242 }
00243
00244
00245
00246
00247
00248 static void release_msbrowse_name_fail( struct subnet_record *subrec,
00249 struct response_record *rrec,
00250 struct nmb_name *fail_name)
00251 {
00252 struct name_record *namerec;
00253
00254 DEBUG(4,("release_msbrowse_name_fail: Failed to release name %s on subnet %s\n.",
00255 nmb_namestr(fail_name), subrec->subnet_name ));
00256
00257
00258 namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
00259 if(namerec)
00260 remove_name_from_namelist(subrec, namerec);
00261
00262
00263 remove_permanent_name_from_unicast( subrec, fail_name);
00264 }
00265
00266
00267
00268
00269
00270
00271 void unbecome_local_master_browser(struct subnet_record *subrec, struct work_record *work,
00272 BOOL force_new_election)
00273 {
00274 struct name_record *namerec;
00275 struct nmb_name nmbname;
00276
00277
00278
00279 DEBUG(2,("unbecome_local_master_browser: unbecoming local master for workgroup %s \
00280 on subnet %s\n",work->work_group, subrec->subnet_name));
00281
00282 if(find_server_in_workgroup( work, global_myname()) == NULL) {
00283 DEBUG(0,("unbecome_local_master_browser: Error - cannot find server %s \
00284 in workgroup %s on subnet %s\n",
00285 global_myname(), work->work_group, subrec->subnet_name));
00286 work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
00287 return;
00288 }
00289
00290
00291 work->mst_state = MST_UNBECOMING_MASTER;
00292
00293
00294
00295
00296
00297
00298 release_1d_name( subrec, work->work_group, force_new_election);
00299
00300
00301 make_nmb_name(&nmbname, MSBROWSE, 0x1);
00302 if((namerec = find_name_on_subnet( subrec, &nmbname, FIND_SELF_NAME))!=NULL) {
00303 release_name(subrec, namerec,
00304 release_msbrowse_name_success,
00305 release_msbrowse_name_fail,
00306 NULL);
00307 }
00308
00309
00310
00311
00312
00313
00314
00315 retransmit_or_expire_response_records(time(NULL));
00316 }
00317
00318
00319
00320
00321
00322
00323 static void become_local_master_stage2(struct subnet_record *subrec,
00324 struct userdata_struct *userdata,
00325 struct nmb_name *registered_name,
00326 uint16 nb_flags,
00327 int ttl, struct in_addr registered_ip)
00328 {
00329 int i = 0;
00330 struct server_record *sl;
00331 struct work_record *work;
00332 struct server_record *servrec;
00333 unstring regname;
00334
00335 pull_ascii_nstring(regname, sizeof(regname), registered_name->name);
00336 work = find_workgroup_on_subnet( subrec, regname);
00337
00338 if(!work) {
00339 DEBUG(0,("become_local_master_stage2: Error - cannot find \
00340 workgroup %s on subnet %s\n", regname, subrec->subnet_name));
00341 return;
00342 }
00343
00344 if((servrec = find_server_in_workgroup( work, global_myname())) == NULL) {
00345 DEBUG(0,("become_local_master_stage2: Error - cannot find server %s \
00346 in workgroup %s on subnet %s\n",
00347 global_myname(), regname, subrec->subnet_name));
00348 work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
00349 return;
00350 }
00351
00352 DEBUG(3,("become_local_master_stage2: registered as master browser for workgroup %s \
00353 on subnet %s\n", work->work_group, subrec->subnet_name));
00354
00355 work->mst_state = MST_BROWSER;
00356
00357
00358 servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
00359 servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
00360
00361
00362 subrec->work_changed = True;
00363
00364
00365 set_workgroup_local_master_browser_name( work, global_myname());
00366
00367
00368
00369
00370
00371 for( sl = work->serverlist; sl != NULL; sl = sl->next)
00372 i++;
00373
00374 if (i < 10) {
00375
00376 broadcast_announce_request(subrec, work);
00377 }
00378
00379
00380
00381
00382
00383
00384
00385
00386
00387
00388
00389
00390 insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
00391
00392
00393
00394 reset_announce_timer();
00395
00396 if( DEBUGLVL( 0 ) ) {
00397 dbgtext( "*****\n\n" );
00398 dbgtext( "Samba name server %s ", global_myname() );
00399 dbgtext( "is now a local master browser " );
00400 dbgtext( "for workgroup %s ", work->work_group );
00401 dbgtext( "on subnet %s\n\n*****\n", subrec->subnet_name );
00402 }
00403 }
00404
00405
00406
00407
00408
00409 static void become_local_master_fail2(struct subnet_record *subrec,
00410 struct response_record *rrec,
00411 struct nmb_name *fail_name)
00412 {
00413 unstring failname;
00414 struct work_record *work;
00415
00416 DEBUG(0,("become_local_master_fail2: failed to register name %s on subnet %s. \
00417 Failed to become a local master browser.\n", nmb_namestr(fail_name), subrec->subnet_name));
00418
00419 pull_ascii_nstring(failname, sizeof(failname), fail_name->name);
00420 work = find_workgroup_on_subnet( subrec, failname);
00421
00422 if(!work) {
00423 DEBUG(0,("become_local_master_fail2: Error - cannot find \
00424 workgroup %s on subnet %s\n", failname, subrec->subnet_name));
00425 return;
00426 }
00427
00428
00429 unbecome_local_master_browser(subrec, work, False);
00430 }
00431
00432
00433
00434
00435
00436 static void become_local_master_stage1(struct subnet_record *subrec,
00437 struct userdata_struct *userdata,
00438 struct nmb_name *registered_name,
00439 uint16 nb_flags,
00440 int ttl, struct in_addr registered_ip)
00441 {
00442 char *work_name = userdata->data;
00443 struct work_record *work = find_workgroup_on_subnet( subrec, work_name);
00444
00445 if(!work) {
00446 DEBUG(0,("become_local_master_stage1: Error - cannot find \
00447 %s on subnet %s\n", work_name, subrec->subnet_name));
00448 return;
00449 }
00450
00451 DEBUG(3,("become_local_master_stage1: go to stage 2: register the %s<1d> name.\n",
00452 work->work_group));
00453
00454 work->mst_state = MST_MSB;
00455
00456
00457
00458
00459
00460
00461
00462
00463 insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
00464
00465
00466 register_name(subrec, work->work_group,0x1d,samba_nb_type,
00467 become_local_master_stage2,
00468 become_local_master_fail2,
00469 NULL);
00470 }
00471
00472
00473
00474
00475
00476 static void become_local_master_fail1(struct subnet_record *subrec,
00477 struct response_record *rrec,
00478 struct nmb_name *fail_name)
00479 {
00480 char *work_name = rrec->userdata->data;
00481 struct work_record *work = find_workgroup_on_subnet(subrec, work_name);
00482
00483 if(!work) {
00484 DEBUG(0,("become_local_master_fail1: Error - cannot find \
00485 workgroup %s on subnet %s\n", work_name, subrec->subnet_name));
00486 return;
00487 }
00488
00489 if(find_server_in_workgroup(work, global_myname()) == NULL) {
00490 DEBUG(0,("become_local_master_fail1: Error - cannot find server %s \
00491 in workgroup %s on subnet %s\n",
00492 global_myname(), work->work_group, subrec->subnet_name));
00493 return;
00494 }
00495
00496 reset_workgroup_state( subrec, work->work_group, False );
00497
00498 DEBUG(0,("become_local_master_fail1: Failed to become a local master browser for \
00499 workgroup %s on subnet %s. Couldn't register name %s.\n",
00500 work->work_group, subrec->subnet_name, nmb_namestr(fail_name)));
00501 }
00502
00503
00504
00505
00506
00507
00508
00509
00510
00511
00512 void become_local_master_browser(struct subnet_record *subrec, struct work_record *work)
00513 {
00514 struct userdata_struct *userdata;
00515 size_t size = sizeof(struct userdata_struct) + sizeof(fstring) + 1;
00516
00517
00518 if (!lp_local_master()) {
00519 DEBUG(0,("become_local_master_browser: Samba not configured as a local master browser.\n"));
00520 return;
00521 }
00522
00523 if(!AM_POTENTIAL_MASTER_BROWSER(work)) {
00524 DEBUG(2,("become_local_master_browser: Awaiting potential browser state. Current state is %d\n",
00525 work->mst_state ));
00526 return;
00527 }
00528
00529 if(find_server_in_workgroup( work, global_myname()) == NULL) {
00530 DEBUG(0,("become_local_master_browser: Error - cannot find server %s \
00531 in workgroup %s on subnet %s\n",
00532 global_myname(), work->work_group, subrec->subnet_name));
00533 return;
00534 }
00535
00536 DEBUG(2,("become_local_master_browser: Starting to become a master browser for workgroup \
00537 %s on subnet %s\n", work->work_group, subrec->subnet_name));
00538
00539 DEBUG(3,("become_local_master_browser: first stage - attempt to register ^1^2__MSBROWSE__^2^1\n"));
00540 work->mst_state = MST_BACKUP;
00541
00542 work->ElectionCriterion |= 0x5;
00543
00544
00545 subrec->work_changed = True;
00546
00547
00548 if((userdata = (struct userdata_struct *)SMB_MALLOC(size)) == NULL) {
00549 DEBUG(0,("become_local_master_browser: malloc fail.\n"));
00550 return;
00551 }
00552
00553 userdata->copy_fn = NULL;
00554 userdata->free_fn = NULL;
00555 userdata->userdata_len = strlen(work->work_group)+1;
00556 overmalloc_safe_strcpy(userdata->data, work->work_group, size - sizeof(*userdata) - 1);
00557
00558
00559 register_name(subrec, MSBROWSE, 0x01, samba_nb_type|NB_GROUP,
00560 become_local_master_stage1,
00561 become_local_master_fail1,
00562 userdata);
00563
00564 zero_free(userdata, size);
00565 }
00566
00567
00568
00569
00570
00571
00572
00573
00574 void set_workgroup_local_master_browser_name( struct work_record *work, const char *newname)
00575 {
00576 DEBUG(5,("set_workgroup_local_master_browser_name: setting local master name to '%s' \
00577 for workgroup %s.\n", newname, work->work_group ));
00578
00579 #if 0
00580
00581
00582
00583
00584 if(strequal( work->work_group, newname))
00585 {
00586 DEBUG(5, ("set_workgroup_local_master_browser_name: Refusing to set \
00587 local_master_browser_name for workgroup %s to workgroup name.\n",
00588 work->work_group ));
00589 return;
00590 }
00591 #endif
00592
00593 unstrcpy(work->local_master_browser_name, newname);
00594 }