nmbd/nmbd_sendannounce.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-1998
00007 
00008    SMB Version handling
00009    Copyright (C) John H Terpstra 1995-1998
00010    
00011    This program is free software; you can redistribute it and/or modify
00012    it under the terms of the GNU General Public License as published by
00013    the Free Software Foundation; either version 2 of the License, or
00014    (at your option) any later version.
00015    
00016    This program is distributed in the hope that it will be useful,
00017    but WITHOUT ANY WARRANTY; without even the implied warranty of
00018    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019    GNU General Public License for more details.
00020    
00021    You should have received a copy of the GNU General Public License
00022    along with this program; if not, write to the Free Software
00023    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00024    
00025 */
00026 
00027 #include "includes.h"
00028 
00029 extern int  updatecount;
00030 extern BOOL found_lm_clients;
00031 
00032 /****************************************************************************
00033  Send a browser reset packet.
00034 **************************************************************************/
00035 
00036 void send_browser_reset(int reset_type, const char *to_name, int to_type, struct in_addr to_ip)
00037 {
00038         char outbuf[PSTRING_LEN];
00039         char *p;
00040 
00041         DEBUG(3,("send_browser_reset: sending reset request type %d to %s<%02x> IP %s.\n",
00042                 reset_type, to_name, to_type, inet_ntoa(to_ip) ));
00043 
00044         memset(outbuf,'\0',sizeof(outbuf));
00045         p = outbuf;
00046         SCVAL(p,0,ANN_ResetBrowserState);
00047         p++;
00048         SCVAL(p,0,reset_type);
00049         p++;
00050 
00051         send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
00052                 global_myname(), 0x0, to_name, to_type, to_ip, 
00053                 FIRST_SUBNET->myip, DGRAM_PORT);
00054 }
00055 
00056 /****************************************************************************
00057   Broadcast a packet to the local net requesting that all servers in this
00058   workgroup announce themselves to us.
00059   **************************************************************************/
00060 
00061 void broadcast_announce_request(struct subnet_record *subrec, struct work_record *work)
00062 {
00063         char outbuf[PSTRING_LEN];
00064         char *p;
00065 
00066         work->needannounce = True;
00067 
00068         DEBUG(3,("broadcast_announce_request: sending announce request for workgroup %s \
00069 to subnet %s\n", work->work_group, subrec->subnet_name));
00070 
00071         memset(outbuf,'\0',sizeof(outbuf));
00072         p = outbuf;
00073         SCVAL(p,0,ANN_AnnouncementRequest);
00074         p++;
00075 
00076         SCVAL(p,0,work->token); /* (local) Unique workgroup token id. */
00077         p++;
00078         p +=  push_string(NULL, p+1, global_myname(), 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
00079   
00080         send_mailslot(False, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
00081                 global_myname(), 0x0, work->work_group,0x1e, subrec->bcast_ip, 
00082                 subrec->myip, DGRAM_PORT);
00083 }
00084 
00085 /****************************************************************************
00086   Broadcast an announcement.
00087   **************************************************************************/
00088 
00089 static void send_announcement(struct subnet_record *subrec, int announce_type,
00090                               const char *from_name, const char *to_name, int to_type, struct in_addr to_ip,
00091                               time_t announce_interval,
00092                               const char *server_name, int server_type, const char *server_comment)
00093 {
00094         char outbuf[PSTRING_LEN];
00095         unstring upper_server_name;
00096         char *p;
00097 
00098         memset(outbuf,'\0',sizeof(outbuf));
00099         p = outbuf+1;
00100 
00101         SCVAL(outbuf,0,announce_type);
00102 
00103         /* Announcement parameters. */
00104         SCVAL(p,0,updatecount);
00105         SIVAL(p,1,announce_interval*1000); /* Milliseconds - despite the spec. */
00106 
00107         safe_strcpy(upper_server_name, server_name, sizeof(upper_server_name)-1);
00108         strupper_m(upper_server_name);
00109         push_string(NULL, p+5, upper_server_name, 16, STR_ASCII|STR_TERMINATE);
00110 
00111         SCVAL(p,21,lp_major_announce_version()); /* Major version. */
00112         SCVAL(p,22,lp_minor_announce_version()); /* Minor version. */
00113 
00114         SIVAL(p,23,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
00115         /* Browse version: got from NT/AS 4.00  - Value defined in smb.h (JHT). */
00116         SSVAL(p,27,BROWSER_ELECTION_VERSION);
00117         SSVAL(p,29,BROWSER_CONSTANT); /* Browse signature. */
00118 
00119         p += 31 + push_string(NULL, p+31, server_comment, sizeof(outbuf) - (p + 31 - outbuf), STR_ASCII|STR_TERMINATE);
00120 
00121         send_mailslot(False,BROWSE_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
00122                         from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
00123                         DGRAM_PORT);
00124 }
00125 
00126 /****************************************************************************
00127   Broadcast a LanMan announcement.
00128 **************************************************************************/
00129 
00130 static void send_lm_announcement(struct subnet_record *subrec, int announce_type,
00131                               char *from_name, char *to_name, int to_type, struct in_addr to_ip,
00132                               time_t announce_interval,
00133                               char *server_name, int server_type, char *server_comment)
00134 {
00135         char outbuf[PSTRING_LEN];
00136         char *p=outbuf;
00137 
00138         memset(outbuf,'\0',sizeof(outbuf));
00139 
00140         SSVAL(p,0,announce_type);
00141         SIVAL(p,2,server_type & ~SV_TYPE_LOCAL_LIST_ONLY);
00142         SCVAL(p,6,lp_major_announce_version()); /* Major version. */
00143         SCVAL(p,7,lp_minor_announce_version()); /* Minor version. */
00144         SSVAL(p,8,announce_interval);            /* In seconds - according to spec. */
00145 
00146         p += 10;
00147         p += push_string(NULL, p, server_name, 15, STR_ASCII|STR_UPPER|STR_TERMINATE);
00148         p += push_string(NULL, p, server_comment, sizeof(outbuf)- (p - outbuf), STR_ASCII|STR_UPPER|STR_TERMINATE);
00149 
00150         send_mailslot(False,LANMAN_MAILSLOT, outbuf, PTR_DIFF(p,outbuf),
00151                 from_name, 0x0, to_name, to_type, to_ip, subrec->myip,
00152                 DGRAM_PORT);
00153 }
00154 
00155 /****************************************************************************
00156  We are a local master browser. Announce this to WORKGROUP<1e>.
00157 ****************************************************************************/
00158 
00159 static void send_local_master_announcement(struct subnet_record *subrec, struct work_record *work,
00160                                            struct server_record *servrec)
00161 {
00162         /* Ensure we don't have the prohibited bit set. */
00163         uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
00164 
00165         DEBUG(3,("send_local_master_announcement: type %x for name %s on subnet %s for workgroup %s\n",
00166                 type, global_myname(), subrec->subnet_name, work->work_group));
00167 
00168         send_announcement(subrec, ANN_LocalMasterAnnouncement,
00169                         global_myname(),                 /* From nbt name. */
00170                         work->work_group, 0x1e,          /* To nbt name. */
00171                         subrec->bcast_ip,                /* To ip. */
00172                         work->announce_interval,         /* Time until next announce. */
00173                         global_myname(),                 /* Name to announce. */
00174                         type,                            /* Type field. */
00175                         servrec->serv.comment);
00176 }
00177 
00178 /****************************************************************************
00179  Announce the workgroup WORKGROUP to MSBROWSE<01>.
00180 ****************************************************************************/
00181 
00182 static void send_workgroup_announcement(struct subnet_record *subrec, struct work_record *work)
00183 {
00184         DEBUG(3,("send_workgroup_announcement: on subnet %s for workgroup %s\n",
00185                 subrec->subnet_name, work->work_group));
00186 
00187         send_announcement(subrec, ANN_DomainAnnouncement,
00188                         global_myname(),                 /* From nbt name. */
00189                         MSBROWSE, 0x1,                   /* To nbt name. */
00190                         subrec->bcast_ip,                /* To ip. */
00191                         work->announce_interval,         /* Time until next announce. */
00192                         work->work_group,                /* Name to announce. */
00193                         SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT,  /* workgroup announce flags. */
00194                         global_myname());                /* From name as comment. */
00195 }
00196 
00197 /****************************************************************************
00198  Announce the given host to WORKGROUP<1d>.
00199 ****************************************************************************/
00200 
00201 static void send_host_announcement(struct subnet_record *subrec, struct work_record *work,
00202                                    struct server_record *servrec)
00203 {
00204         /* Ensure we don't have the prohibited bits set. */
00205         uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
00206 
00207         DEBUG(3,("send_host_announcement: type %x for host %s on subnet %s for workgroup %s\n",
00208                 type, servrec->serv.name, subrec->subnet_name, work->work_group));
00209 
00210         send_announcement(subrec, ANN_HostAnnouncement,
00211                         servrec->serv.name,              /* From nbt name. */
00212                         work->work_group, 0x1d,          /* To nbt name. */
00213                         subrec->bcast_ip,                /* To ip. */
00214                         work->announce_interval,         /* Time until next announce. */
00215                         servrec->serv.name,              /* Name to announce. */
00216                         type,                            /* Type field. */
00217                         servrec->serv.comment);
00218 }
00219 
00220 /****************************************************************************
00221  Announce the given LanMan host
00222 ****************************************************************************/
00223 
00224 static void send_lm_host_announcement(struct subnet_record *subrec, struct work_record *work,
00225                                    struct server_record *servrec, int lm_interval)
00226 {
00227         /* Ensure we don't have the prohibited bits set. */
00228         uint32 type = servrec->serv.type & ~SV_TYPE_LOCAL_LIST_ONLY;
00229 
00230         DEBUG(3,("send_lm_host_announcement: type %x for host %s on subnet %s for workgroup %s, ttl: %d\n",
00231                 type, servrec->serv.name, subrec->subnet_name, work->work_group, lm_interval));
00232 
00233         send_lm_announcement(subrec, ANN_HostAnnouncement,
00234                         servrec->serv.name,              /* From nbt name. */
00235                         work->work_group, 0x00,          /* To nbt name. */
00236                         subrec->bcast_ip,                /* To ip. */
00237                         lm_interval,                     /* Time until next announce. */
00238                         servrec->serv.name,              /* Name to announce (fstring not netbios name struct). */
00239                         type,                            /* Type field. */
00240                         servrec->serv.comment);
00241 }
00242 
00243 /****************************************************************************
00244   Announce a server record.
00245   ****************************************************************************/
00246 
00247 static void announce_server(struct subnet_record *subrec, struct work_record *work,
00248                      struct server_record *servrec)
00249 {
00250         /* Only do domain announcements if we are a master and it's
00251                 our primary name we're being asked to announce. */
00252 
00253         if (AM_LOCAL_MASTER_BROWSER(work) && strequal(global_myname(),servrec->serv.name)) {
00254                 send_local_master_announcement(subrec, work, servrec);
00255                 send_workgroup_announcement(subrec, work);
00256         } else {
00257                 send_host_announcement(subrec, work, servrec);
00258         }
00259 }
00260 
00261 /****************************************************************************
00262   Go through all my registered names on all broadcast subnets and announce
00263   them if the timeout requires it.
00264   **************************************************************************/
00265 
00266 void announce_my_server_names(time_t t)
00267 {
00268         struct subnet_record *subrec;
00269 
00270         for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
00271                 struct work_record *work = find_workgroup_on_subnet(subrec, lp_workgroup());
00272 
00273                 if(work) {
00274                         struct server_record *servrec;
00275 
00276                         if (work->needannounce) {
00277                                 /* Drop back to a max 3 minute announce. This is to prevent a
00278                                         single lost packet from breaking things for too long. */
00279 
00280                                 work->announce_interval = MIN(work->announce_interval,
00281                                                         CHECK_TIME_MIN_HOST_ANNCE*60);
00282                                 work->lastannounce_time = t - (work->announce_interval+1);
00283                                 work->needannounce = False;
00284                         }
00285 
00286                         /* Announce every minute at first then progress to every 12 mins */
00287                         if ((t - work->lastannounce_time) < work->announce_interval)
00288                                 continue;
00289 
00290                         if (work->announce_interval < (CHECK_TIME_MAX_HOST_ANNCE * 60))
00291                                 work->announce_interval += 60;
00292 
00293                         work->lastannounce_time = t;
00294 
00295                         for (servrec = work->serverlist; servrec; servrec = servrec->next) {
00296                                 if (is_myname(servrec->serv.name))
00297                                         announce_server(subrec, work, servrec);
00298                         }
00299                 } /* if work */
00300         } /* for subrec */
00301 }
00302 
00303 /****************************************************************************
00304   Go through all my registered names on all broadcast subnets and announce
00305   them as a LanMan server if the timeout requires it.
00306 **************************************************************************/
00307 
00308 void announce_my_lm_server_names(time_t t)
00309 {
00310         struct subnet_record *subrec;
00311         static time_t last_lm_announce_time=0;
00312         int announce_interval = lp_lm_interval();
00313         int lm_announce = lp_lm_announce();
00314 
00315         if ((announce_interval <= 0) || (lm_announce <= 0)) {
00316                 /* user absolutely does not want LM announcements to be sent. */
00317                 return;
00318         }
00319 
00320         if ((lm_announce >= 2) && (!found_lm_clients)) {
00321                 /* has been set to 2 (Auto) but no LM clients detected (yet). */
00322                 return;
00323         }
00324 
00325         /* Otherwise: must have been set to 1 (Yes), or LM clients *have*
00326                 been detected. */
00327 
00328         for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
00329                 struct work_record *work = find_workgroup_on_subnet(subrec, lp_workgroup());
00330 
00331                 if(work) {
00332                         struct server_record *servrec;
00333 
00334                         if (last_lm_announce_time && ((t - last_lm_announce_time) < announce_interval ))
00335                                 continue;
00336 
00337                         last_lm_announce_time = t;
00338 
00339                         for (servrec = work->serverlist; servrec; servrec = servrec->next) {
00340                                 if (is_myname(servrec->serv.name))
00341                                         /* skipping equivalent of announce_server() */
00342                                         send_lm_host_announcement(subrec, work, servrec, announce_interval);
00343                         }
00344                 } /* if work */
00345         } /* for subrec */
00346 }
00347 
00348 /* Announce timer. Moved into global static so it can be reset
00349    when a machine becomes a local master browser. */
00350 static time_t announce_timer_last=0;
00351 
00352 /****************************************************************************
00353  Reset the announce_timer so that a local master browser announce will be done
00354  immediately.
00355  ****************************************************************************/
00356 
00357 void reset_announce_timer(void)
00358 {
00359         announce_timer_last = time(NULL) - (CHECK_TIME_MST_ANNOUNCE * 60);
00360 }
00361 
00362 /****************************************************************************
00363   Announce myself as a local master browser to a domain master browser.
00364   **************************************************************************/
00365 
00366 void announce_myself_to_domain_master_browser(time_t t)
00367 {
00368         struct subnet_record *subrec;
00369         struct work_record *work;
00370 
00371         if(!we_are_a_wins_client()) {
00372                 DEBUG(10,("announce_myself_to_domain_master_browser: no unicast subnet, ignoring.\n"));
00373                 return;
00374         }
00375 
00376         if (!announce_timer_last)
00377                 announce_timer_last = t;
00378 
00379         if ((t-announce_timer_last) < (CHECK_TIME_MST_ANNOUNCE * 60)) {
00380                 DEBUG(10,("announce_myself_to_domain_master_browser: t (%d) - last(%d) < %d\n",
00381                         (int)t, (int)announce_timer_last, 
00382                         CHECK_TIME_MST_ANNOUNCE * 60 ));
00383                 return;
00384         }
00385 
00386         announce_timer_last = t;
00387 
00388         /* Look over all our broadcast subnets to see if any of them
00389                 has the state set as local master browser. */
00390 
00391         for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
00392                 for (work = subrec->workgrouplist; work; work = work->next) {
00393                         if (AM_LOCAL_MASTER_BROWSER(work)) {
00394                                 DEBUG(4,( "announce_myself_to_domain_master_browser: I am a local master browser for \
00395 workgroup %s on subnet %s\n", work->work_group, subrec->subnet_name));
00396 
00397                                 /* Look in nmbd_browsersync.c for the rest of this code. */
00398                                 announce_and_sync_with_domain_master_browser(subrec, work);
00399                         }
00400                 }
00401         }
00402 }
00403 
00404 /****************************************************************************
00405 Announce all samba's server entries as 'gone'.
00406 This must *only* be called on shutdown.
00407 ****************************************************************************/
00408 
00409 void announce_my_servers_removed(void)
00410 {
00411         int announce_interval = lp_lm_interval();
00412         int lm_announce = lp_lm_announce();
00413         struct subnet_record *subrec; 
00414 
00415         for (subrec = FIRST_SUBNET; subrec; subrec = NEXT_SUBNET_EXCLUDING_UNICAST(subrec)) {
00416                 struct work_record *work;
00417                 for (work = subrec->workgrouplist; work; work = work->next) {
00418                         struct server_record *servrec;
00419 
00420                         work->announce_interval = 0;
00421                         for (servrec = work->serverlist; servrec; servrec = servrec->next) {
00422                                 if (!is_myname(servrec->serv.name))
00423                                         continue;
00424                                 servrec->serv.type = 0;
00425                                 if(AM_LOCAL_MASTER_BROWSER(work))
00426                                         send_local_master_announcement(subrec, work, servrec);
00427                                 send_host_announcement(subrec, work, servrec);
00428 
00429                                 if ((announce_interval <= 0) || (lm_announce <= 0)) {
00430                                         /* user absolutely does not want LM announcements to be sent. */
00431                                         continue;
00432                                 }
00433 
00434                                 if ((lm_announce >= 2) && (!found_lm_clients)) {
00435                                         /* has been set to 2 (Auto) but no LM clients detected (yet). */
00436                                         continue;
00437                                 }
00438 
00439                                 /* 
00440                                  * lm announce was set or we have seen lm announcements, so do
00441                                  * a lm announcement of host removed.
00442                                  */
00443 
00444                                 send_lm_host_announcement(subrec, work, servrec, 0);
00445                         }
00446                 }
00447         }
00448 }
00449 
00450 /****************************************************************************
00451   Do all the "remote" announcements. These are used to put ourselves
00452   on a remote browse list. They are done blind, no checking is done to
00453   see if there is actually a local master browser at the other end.
00454   **************************************************************************/
00455 
00456 void announce_remote(time_t t)
00457 {
00458         char *s;
00459         const char *ptr;
00460         static time_t last_time = 0;
00461         pstring s2;
00462         struct in_addr addr;
00463         char *comment;
00464         int stype = lp_default_server_announce();
00465 
00466         if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
00467                 return;
00468 
00469         last_time = t;
00470 
00471         s = lp_remote_announce();
00472         if (!*s)
00473                 return;
00474 
00475         comment = string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH);
00476 
00477         for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); ) {
00478                 /* The entries are of the form a.b.c.d/WORKGROUP with 
00479                                 WORKGROUP being optional */
00480                 const char *wgroup;
00481                 char *pwgroup;
00482                 int i;
00483 
00484                 pwgroup = strchr_m(s2,'/');
00485                 if (pwgroup)
00486                         *pwgroup++ = 0;
00487                 if (!pwgroup || !*pwgroup)
00488                         wgroup = lp_workgroup();
00489                 else
00490                         wgroup = pwgroup;
00491 
00492                 addr = *interpret_addr2(s2);
00493     
00494                 /* Announce all our names including aliases */
00495                 /* Give the ip address as the address of our first
00496                                 broadcast subnet. */
00497 
00498                 for(i=0; my_netbios_names(i); i++) {
00499                         const char *name = my_netbios_names(i);
00500 
00501                         DEBUG(5,("announce_remote: Doing remote announce for server %s to IP %s.\n",
00502                                 name, inet_ntoa(addr) ));
00503 
00504                         send_announcement(FIRST_SUBNET, ANN_HostAnnouncement,
00505                                                 name,                      /* From nbt name. */
00506                                                 wgroup, 0x1d,              /* To nbt name. */
00507                                                 addr,                      /* To ip. */
00508                                                 REMOTE_ANNOUNCE_INTERVAL,  /* Time until next announce. */
00509                                                 name,                      /* Name to announce. */
00510                                                 stype,                     /* Type field. */
00511                                                 comment);
00512                 }
00513         }
00514 }
00515 
00516 /****************************************************************************
00517   Implement the 'remote browse sync' feature Andrew added.
00518   These are used to put our browse lists into remote browse lists.
00519 **************************************************************************/
00520 
00521 void browse_sync_remote(time_t t)
00522 {  
00523         char *s;
00524         const char *ptr;
00525         static time_t last_time = 0; 
00526         pstring s2;
00527         struct in_addr addr;
00528         struct work_record *work;
00529         pstring outbuf;
00530         char *p;
00531         unstring myname;
00532  
00533         if (last_time && (t < (last_time + REMOTE_ANNOUNCE_INTERVAL)))
00534                 return;
00535    
00536         last_time = t;
00537 
00538         s = lp_remote_browse_sync();
00539         if (!*s)
00540                 return;
00541 
00542         /*
00543          * We only do this if we are the local master browser
00544          * for our workgroup on the firsst subnet.
00545          */
00546 
00547         if((work = find_workgroup_on_subnet(FIRST_SUBNET, lp_workgroup())) == NULL) {   
00548                 DEBUG(0,("browse_sync_remote: Cannot find workgroup %s on subnet %s\n",
00549                         lp_workgroup(), FIRST_SUBNET->subnet_name ));
00550                 return;
00551         }
00552          
00553         if(!AM_LOCAL_MASTER_BROWSER(work)) {
00554                 DEBUG(5,("browse_sync_remote: We can only do this if we are a local master browser \
00555 for workgroup %s on subnet %s.\n", lp_workgroup(), FIRST_SUBNET->subnet_name ));
00556                 return;
00557         } 
00558 
00559         memset(outbuf,'\0',sizeof(outbuf));
00560         p = outbuf;
00561         SCVAL(p,0,ANN_MasterAnnouncement);
00562         p++;
00563 
00564         unstrcpy(myname, global_myname());
00565         strupper_m(myname);
00566         myname[15]='\0';
00567         push_pstring_base(p, myname, outbuf);
00568 
00569         p = skip_string(outbuf,sizeof(outbuf),p);
00570 
00571         for (ptr=s; next_token(&ptr,s2,NULL,sizeof(s2)); ) {
00572                 /* The entries are of the form a.b.c.d */
00573                 addr = *interpret_addr2(s2);
00574 
00575                 DEBUG(5,("announce_remote: Doing remote browse sync announce for server %s to IP %s.\n",
00576                         global_myname(), inet_ntoa(addr) ));
00577 
00578                 send_mailslot(True, BROWSE_MAILSLOT, outbuf,PTR_DIFF(p,outbuf),
00579                         global_myname(), 0x0, "*", 0x0, addr, FIRST_SUBNET->myip, DGRAM_PORT);
00580         }
00581 }

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