nmbd/nmbd_become_lmb.c

説明を見る。
00001 /* 
00002    Unix SMB/CIFS implementation.
00003    NBT netbios routines and daemon - version 2
00004    Copyright (C) Andrew Tridgell 1994-1998
00005    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
00006    Copyright (C) Jeremy Allison 1994-2003
00007    
00008    This program is free software; you can redistribute it and/or modify
00009    it under the terms of the GNU General Public License as published by
00010    the Free Software Foundation; either version 2 of the License, or
00011    (at your option) any later version.
00012    
00013    This program is distributed in the hope that it will be useful,
00014    but WITHOUT ANY WARRANTY; without even the implied warranty of
00015    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00016    GNU General Public License for more details.
00017    
00018    You should have received a copy of the GNU General Public License
00019    along with this program; if not, write to the Free Software
00020    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00021    
00022 */
00023 
00024 #include "includes.h"
00025 
00026 extern uint16 samba_nb_type; /* Samba's NetBIOS name type. */
00027 
00028 /*******************************************************************
00029  Utility function to add a name to the unicast subnet, or add in
00030  our IP address if it already exists.
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                 /* The name needs to be created on the unicast subnet. */
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                 /* The name already exists on the unicast subnet. Add our local
00047                 IP for the given broadcast subnet to the name. */
00048                 add_ip_to_name_record( namerec, subrec->myip);
00049         }
00050 }
00051 
00052 /*******************************************************************
00053  Utility function to remove a name from the unicast subnet.
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                 /* Remove this broadcast subnet IP address from the name. */
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  Utility function always called to set our workgroup and server
00071  state back to potential browser, or none.
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         /* Update our server status - remove any master flag and replace
00096                 it with the potential browser flag. */
00097         servrec->serv.type &= ~SV_TYPE_MASTER_BROWSER;
00098         servrec->serv.type |= (lp_local_master() ? SV_TYPE_POTENTIAL_BROWSER : 0);
00099 
00100         /* Tell the namelist writer to write out a change. */
00101         subrec->work_changed = True;
00102 
00103         /* Reset our election flags. */
00104         work->ElectionCriterion &= ~0x4;
00105 
00106         work->mst_state = lp_local_master() ? MST_POTENTIAL : MST_NONE;
00107 
00108         /* Forget who the local master browser was for
00109                 this workgroup. */
00110 
00111         set_workgroup_local_master_browser_name( work, "");
00112 
00113         /*
00114          * Ensure the IP address of this subnet is not registered as one
00115          * of the IP addresses of the WORKGROUP<1d> name on the unicast
00116          * subnet. This undoes what we did below when we became a local
00117          * master browser.
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   Unbecome the local master browser name release success function.
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         /* Now reset the workgroup and server state. */
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   Unbecome the local master browser name release fail function.
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         /* Do it anyway. */
00177         namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
00178         if(namerec)
00179                 remove_name_from_namelist(subrec, namerec);
00180 
00181         /* Now reset the workgroup and server state. */
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  Utility function to remove the WORKGROUP<1d> name.
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  Unbecome the local master browser MSBROWSE name release success function.
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         /* Remove the permanent MSBROWSE name added into the unicast subnet. */
00241         remove_permanent_name_from_unicast( subrec, released_name);
00242 }
00243 
00244 /*******************************************************************
00245  Unbecome the local master browser MSBROWSE name release fail function.
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         /* Release the name anyway. */
00258         namerec = find_name_on_subnet(subrec, fail_name, FIND_SELF_NAME);
00259         if(namerec)
00260                 remove_name_from_namelist(subrec, namerec);
00261 
00262         /* Remove the permanent MSBROWSE name added into the unicast subnet. */
00263         remove_permanent_name_from_unicast( subrec, fail_name);
00264 }
00265 
00266 /*******************************************************************
00267   Unbecome the local master browser. If force_new_election is true, restart
00268   the election process after we've unbecome the local master.
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   /* Sanity check. */
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         /* Set the state to unbecoming. */
00291         work->mst_state = MST_UNBECOMING_MASTER;
00292 
00293         /*
00294          * Release the WORKGROUP<1d> name asap to allow another machine to
00295          * claim it.
00296          */
00297 
00298         release_1d_name( subrec, work->work_group, force_new_election);
00299 
00300         /* Deregister any browser names we may have. */
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          * Ensure we have sent and processed these release packets
00311          * before returning - we don't want to process any election
00312          * packets before dealing with the 1d release.
00313          */
00314 
00315         retransmit_or_expire_response_records(time(NULL));
00316 }
00317 
00318 /****************************************************************************
00319   Success in registering the WORKGROUP<1d> name.
00320   We are now *really* a local master browser.
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; /* registering WORKGROUP(1d) succeeded */
00356 
00357         /* update our server status */
00358         servrec->serv.type |= SV_TYPE_MASTER_BROWSER;
00359         servrec->serv.type &= ~SV_TYPE_POTENTIAL_BROWSER;
00360 
00361         /* Tell the namelist writer to write out a change. */
00362         subrec->work_changed = True;
00363 
00364         /* Add this name to the workgroup as local master browser. */
00365         set_workgroup_local_master_browser_name( work, global_myname());
00366 
00367         /* Count the number of servers we have on our list. If it's
00368                 less than 10 (just a heuristic) request the servers
00369                 to announce themselves.
00370         */
00371         for( sl = work->serverlist; sl != NULL; sl = sl->next)
00372                 i++;
00373 
00374         if (i < 10) {
00375                 /* Ask all servers on our local net to announce to us. */
00376                 broadcast_announce_request(subrec, work);
00377         }
00378 
00379         /*
00380          * Now we are a local master on a broadcast subnet, we need to add
00381          * the WORKGROUP<1d> name to the unicast subnet so that we can answer
00382          * unicast requests sent to this name. We can create this name directly on
00383          * the unicast subnet as a WINS server always returns true when registering
00384          * this name, and discards the registration. We use the number of IP
00385          * addresses registered to this name as a reference count, as we
00386          * remove this broadcast subnet IP address from it when we stop becoming a local
00387          * master browser for this broadcast subnet.
00388          */
00389 
00390         insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
00391 
00392         /* Reset the announce master browser timer so that we try and tell a domain
00393                 master browser as soon as possible that we are a local master browser. */
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   Failed to register the WORKGROUP<1d> name.
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         /* Roll back all the way by calling unbecome_local_master_browser(). */
00429         unbecome_local_master_browser(subrec, work, False);
00430 }
00431 
00432 /****************************************************************************
00433   Success in registering the MSBROWSE name.
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; /* Registering MSBROWSE was successful. */
00455 
00456         /*
00457          * We registered the MSBROWSE name on a broadcast subnet, now need to add
00458          * the MSBROWSE name to the unicast subnet so that we can answer
00459          * unicast requests sent to this name. We create this name directly on
00460          * the unicast subnet.
00461          */
00462 
00463         insert_permanent_name_into_unicast( subrec, registered_name, nb_flags);
00464 
00465         /* Attempt to register the WORKGROUP<1d> name. */
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   Failed to register the MSBROWSE name.
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   Become the local master browser on a subnet.
00505   This gets called if we win an election on this subnet.
00506 
00507   Stage 1: mst_state was MST_POTENTIAL - go to MST_BACK register ^1^2__MSBROWSE__^2^1.
00508   Stage 2: mst_state was MST_BACKUP  - go to MST_MSB  and register WORKGROUP<1d>.
00509   Stage 3: mst_state was MST_MSB  - go to MST_BROWSER.
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         /* Sanity check. */
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; /* an election win was successful */
00541 
00542         work->ElectionCriterion |= 0x5;
00543 
00544         /* Tell the namelist writer to write out a change. */
00545         subrec->work_changed = True;
00546 
00547         /* Setup the userdata_struct. */
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         /* Register the special browser group name. */
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  Utility function to set the local master browser name. Does
00569  some sanity checking as old versions of Samba seem to sometimes
00570  say that the master browser name for a workgroup is the same
00571  as the workgroup name.
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    * Apparently some sites use the workgroup name as the local
00582    * master browser name. Arrrrggghhhhh ! (JRA).
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 }

Sambaに対してSat Aug 29 21:23:07 2009に生成されました。  doxygen 1.4.7