nmbd/nmbd_serverlistdb.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    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 int updatecount = 0;
00027 
00028 /*******************************************************************
00029   Remove all the servers in a work group.
00030   ******************************************************************/
00031 
00032 void remove_all_servers(struct work_record *work)
00033 {
00034         struct server_record *servrec;
00035         struct server_record *nexts;
00036 
00037         for (servrec = work->serverlist; servrec; servrec = nexts) {
00038                 DEBUG(7,("remove_all_servers: Removing server %s\n",servrec->serv.name));
00039                 nexts = servrec->next;
00040 
00041                 if (servrec->prev)
00042                         servrec->prev->next = servrec->next;
00043                 if (servrec->next)
00044                         servrec->next->prev = servrec->prev;
00045 
00046                 if (work->serverlist == servrec)
00047                         work->serverlist = servrec->next;
00048 
00049                 ZERO_STRUCTP(servrec);
00050                 SAFE_FREE(servrec);
00051         }
00052 
00053         work->subnet->work_changed = True;
00054 }
00055 
00056 /***************************************************************************
00057   Add a server into the a workgroup serverlist.
00058   **************************************************************************/
00059 
00060 static void add_server_to_workgroup(struct work_record *work,
00061                              struct server_record *servrec)
00062 {
00063         struct server_record *servrec2;
00064 
00065         if (!work->serverlist) {
00066                 work->serverlist = servrec;
00067                 servrec->prev = NULL;
00068                 servrec->next = NULL;
00069                 return;
00070         }
00071 
00072         for (servrec2 = work->serverlist; servrec2->next; servrec2 = servrec2->next)
00073                 ;
00074 
00075         servrec2->next = servrec;
00076         servrec->next = NULL;
00077         servrec->prev = servrec2;
00078         work->subnet->work_changed = True;
00079 }
00080 
00081 /****************************************************************************
00082   Find a server in a server list.
00083   **************************************************************************/
00084 
00085 struct server_record *find_server_in_workgroup(struct work_record *work, const char *name)
00086 {
00087         struct server_record *ret;
00088   
00089         for (ret = work->serverlist; ret; ret = ret->next) {
00090                 if (strequal(ret->serv.name,name))
00091                         return ret;
00092         }
00093         return NULL;
00094 }
00095 
00096 
00097 /****************************************************************************
00098   Remove a server entry from this workgroup.
00099   ****************************************************************************/
00100 
00101 void remove_server_from_workgroup(struct work_record *work, struct server_record *servrec)
00102 {
00103         if (servrec->prev)
00104                 servrec->prev->next = servrec->next;
00105         if (servrec->next)
00106                 servrec->next->prev = servrec->prev;
00107 
00108         if (work->serverlist == servrec) 
00109                 work->serverlist = servrec->next; 
00110 
00111         ZERO_STRUCTP(servrec);
00112         SAFE_FREE(servrec);
00113         work->subnet->work_changed = True;
00114 }
00115 
00116 /****************************************************************************
00117   Create a server entry on this workgroup.
00118   ****************************************************************************/
00119 
00120 struct server_record *create_server_on_workgroup(struct work_record *work,
00121                                                  const char *name,int servertype, 
00122                                                  int ttl, const char *comment)
00123 {
00124         struct server_record *servrec;
00125   
00126         if (name[0] == '*') {
00127                 DEBUG(7,("create_server_on_workgroup: not adding name starting with '*' (%s)\n",
00128                         name));
00129                 return (NULL);
00130         }
00131   
00132         if((servrec = find_server_in_workgroup(work, name)) != NULL) {
00133                 DEBUG(0,("create_server_on_workgroup: Server %s already exists on \
00134 workgroup %s. This is a bug.\n", name, work->work_group));
00135                 return NULL;
00136         }
00137   
00138         if((servrec = SMB_MALLOC_P(struct server_record)) == NULL) {
00139                 DEBUG(0,("create_server_entry_on_workgroup: malloc fail !\n"));
00140                 return NULL;
00141         }
00142 
00143         memset((char *)servrec,'\0',sizeof(*servrec));
00144  
00145         servrec->subnet = work->subnet;
00146  
00147         fstrcpy(servrec->serv.name,name);
00148         fstrcpy(servrec->serv.comment,comment);
00149         strupper_m(servrec->serv.name);
00150         servrec->serv.type  = servertype;
00151 
00152         update_server_ttl(servrec, ttl);
00153   
00154         add_server_to_workgroup(work, servrec);
00155       
00156         DEBUG(3,("create_server_on_workgroup: Created server entry %s of type %x (%s) on \
00157 workgroup %s.\n", name,servertype,comment, work->work_group));
00158  
00159         work->subnet->work_changed = True;
00160  
00161         return(servrec);
00162 }
00163 
00164 /*******************************************************************
00165  Update the ttl field of a server record.
00166 *******************************************************************/
00167 
00168 void update_server_ttl(struct server_record *servrec, int ttl)
00169 {
00170         if(ttl > lp_max_ttl())
00171                 ttl = lp_max_ttl();
00172 
00173         if(is_myname(servrec->serv.name))
00174                 servrec->death_time = PERMANENT_TTL;
00175         else
00176                 servrec->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
00177 
00178         servrec->subnet->work_changed = True;
00179 }
00180 
00181 /*******************************************************************
00182   Expire old servers in the serverlist. A time of -1 indicates 
00183   everybody dies except those with a death_time of PERMANENT_TTL (which is 0).
00184   This should only be called from expire_workgroups_and_servers().
00185   ******************************************************************/
00186 
00187 void expire_servers(struct work_record *work, time_t t)
00188 {
00189         struct server_record *servrec;
00190         struct server_record *nexts;
00191   
00192         for (servrec = work->serverlist; servrec; servrec = nexts) {
00193                 nexts = servrec->next;
00194 
00195                 if ((servrec->death_time != PERMANENT_TTL) && ((t == -1) || (servrec->death_time < t))) {
00196                         DEBUG(3,("expire_old_servers: Removing timed out server %s\n",servrec->serv.name));
00197                         remove_server_from_workgroup(work, servrec);
00198                         work->subnet->work_changed = True;
00199                 }
00200         }
00201 }
00202 
00203 /*******************************************************************
00204  Decide if we should write out a server record for this server.
00205  We return zero if we should not. Check if we've already written
00206  out this server record from an earlier subnet.
00207 ******************************************************************/
00208 
00209 static uint32 write_this_server_name( struct subnet_record *subrec,
00210                                       struct work_record *work,
00211                                       struct server_record *servrec)
00212 {
00213         struct subnet_record *ssub;
00214         struct work_record *iwork;
00215 
00216         /* Go through all the subnets we have already seen. */
00217         for (ssub = FIRST_SUBNET; ssub && (ssub != subrec); ssub = NEXT_SUBNET_INCLUDING_UNICAST(ssub)) {
00218                 for(iwork = ssub->workgrouplist; iwork; iwork = iwork->next) {
00219                         if(find_server_in_workgroup( iwork, servrec->serv.name) != NULL) {
00220                                 /*
00221                                  * We have already written out this server record, don't
00222                                  * do it again. This gives precedence to servers we have seen
00223                                  * on the broadcast subnets over servers that may have been
00224                                  * added via a sync on the unicast_subet.
00225                                  *
00226                                  * The correct way to do this is to have a serverlist file
00227                                  * per subnet - this means changes to smbd as well. I may
00228                                  * add this at a later date (JRA).
00229                                  */
00230 
00231                                 return 0;
00232                         }
00233                 }
00234         }
00235 
00236         return servrec->serv.type;
00237 }
00238 
00239 /*******************************************************************
00240  Decide if we should write out a workgroup record for this workgroup.
00241  We return zero if we should not. Don't write out lp_workgroup() (we've
00242  already done it) and also don't write out a second workgroup record
00243  on the unicast subnet that we've already written out on one of the
00244  broadcast subnets.
00245 ******************************************************************/
00246 
00247 static uint32 write_this_workgroup_name( struct subnet_record *subrec, 
00248                                          struct work_record *work)
00249 {
00250         struct subnet_record *ssub;
00251 
00252         if(strequal(lp_workgroup(), work->work_group))
00253                 return 0;
00254 
00255         /* This is a workgroup we have seen on a broadcast subnet. All
00256                 these have the same type. */
00257 
00258         if(subrec != unicast_subnet)
00259                 return (SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY);
00260 
00261         for(ssub = FIRST_SUBNET; ssub;  ssub = NEXT_SUBNET_EXCLUDING_UNICAST(ssub)) {
00262                 /* This is the unicast subnet so check if we've already written out
00263                         this subnet when we passed over the broadcast subnets. */
00264 
00265                 if(find_workgroup_on_subnet( ssub, work->work_group) != NULL)
00266                         return 0;
00267         }
00268 
00269         /* All workgroups on the unicast subnet (except our own, which we
00270                 have already written out) cannot be local. */
00271 
00272         return (SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT);
00273 }
00274 
00275 /*******************************************************************
00276   Write out the browse.dat file.
00277   ******************************************************************/
00278 
00279 void write_browse_list_entry(XFILE *fp, const char *name, uint32 rec_type,
00280                 const char *local_master_browser_name, const char *description)
00281 {
00282         fstring tmp;
00283 
00284         slprintf(tmp,sizeof(tmp)-1, "\"%s\"", name);
00285         x_fprintf(fp, "%-25s ", tmp);
00286         x_fprintf(fp, "%08x ", rec_type);
00287         slprintf(tmp, sizeof(tmp)-1, "\"%s\" ", local_master_browser_name);
00288         x_fprintf(fp, "%-30s", tmp);
00289         x_fprintf(fp, "\"%s\"\n", description);
00290 }
00291 
00292 void write_browse_list(time_t t, BOOL force_write)
00293 {   
00294         struct subnet_record *subrec;
00295         struct work_record *work;
00296         struct server_record *servrec;
00297         pstring fname,fnamenew;
00298         uint32 stype;
00299         int i;
00300         XFILE *fp;
00301         BOOL list_changed = force_write;
00302         static time_t lasttime = 0;
00303     
00304         /* Always dump if we're being told to by a signal. */
00305         if(force_write == False) {
00306                 if (!lasttime)
00307                         lasttime = t;
00308                 if (t - lasttime < 5)
00309                         return;
00310         }
00311 
00312         lasttime = t;
00313 
00314         dump_workgroups(force_write);
00315  
00316         for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
00317                 if(subrec->work_changed) {
00318                         list_changed = True;
00319                         break;
00320                 }
00321         }
00322 
00323         if(!list_changed)
00324                 return;
00325 
00326         updatecount++;
00327     
00328         pstrcpy(fname,lp_lockdir());
00329         trim_char(fname,'\0' ,'/');
00330         pstrcat(fname,"/");
00331         pstrcat(fname,SERVER_LIST);
00332         pstrcpy(fnamenew,fname);
00333         pstrcat(fnamenew,".");
00334  
00335         fp = x_fopen(fnamenew,O_WRONLY|O_CREAT|O_TRUNC, 0644);
00336  
00337         if (!fp) {
00338                 DEBUG(0,("write_browse_list: Can't open file %s. Error was %s\n",
00339                         fnamenew,strerror(errno)));
00340                 return;
00341         } 
00342   
00343         /*
00344          * Write out a record for our workgroup. Use the record from the first
00345          * subnet.
00346          */
00347 
00348         if((work = find_workgroup_on_subnet(FIRST_SUBNET, lp_workgroup())) == NULL) { 
00349                 DEBUG(0,("write_browse_list: Fatal error - cannot find my workgroup %s\n",
00350                         lp_workgroup()));
00351                 x_fclose(fp);
00352                 return;
00353         }
00354 
00355         write_browse_list_entry(fp, work->work_group,
00356                 SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY,
00357                 work->local_master_browser_name, work->work_group);
00358 
00359         /* 
00360          * We need to do something special for our own names.
00361          * This is due to the fact that we may be a local master browser on
00362          * one of our broadcast subnets, and a domain master on the unicast
00363          * subnet. We iterate over the subnets and only write out the name
00364          * once.
00365          */
00366 
00367         for (i=0; my_netbios_names(i); i++) {
00368                 stype = 0;
00369                 for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
00370                         if((work = find_workgroup_on_subnet( subrec, lp_workgroup() )) == NULL)
00371                                 continue;
00372                         if((servrec = find_server_in_workgroup( work, my_netbios_names(i))) == NULL)
00373                                 continue;
00374 
00375                         stype |= servrec->serv.type;
00376                 }
00377 
00378                 /* Output server details, plus what workgroup they're in. */
00379                 write_browse_list_entry(fp, my_netbios_names(i), stype,
00380                         string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH), lp_workgroup());
00381         }
00382       
00383         for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) { 
00384                 subrec->work_changed = False;
00385 
00386                 for (work = subrec->workgrouplist; work ; work = work->next) {
00387                         /* Write out a workgroup record for a workgroup. */
00388                         uint32 wg_type = write_this_workgroup_name( subrec, work);
00389 
00390                         if(wg_type) {
00391                                 write_browse_list_entry(fp, work->work_group, wg_type,
00392                                                 work->local_master_browser_name,
00393                                                 work->work_group);
00394                         }
00395 
00396                         /* Now write out any server records a workgroup may have. */
00397 
00398                         for (servrec = work->serverlist; servrec ; servrec = servrec->next) {
00399                                 uint32 serv_type;
00400 
00401                                 /* We have already written our names here. */
00402                                 if(is_myname(servrec->serv.name))
00403                                         continue; 
00404 
00405                                 serv_type = write_this_server_name(subrec, work, servrec);
00406                                 if(serv_type) {
00407                                         /* Output server details, plus what workgroup they're in. */
00408                                         write_browse_list_entry(fp, servrec->serv.name, serv_type,
00409                                                 servrec->serv.comment, work->work_group);
00410                                 }
00411                         }
00412                 }
00413         } 
00414   
00415         x_fclose(fp);
00416         unlink(fname);
00417         chmod(fnamenew,0644);
00418         rename(fnamenew,fname);
00419         DEBUG(3,("write_browse_list: Wrote browse list into file %s\n",fname));
00420 }

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