root/source3/nmbd/nmbd_serverlistdb.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. remove_all_servers
  2. add_server_to_workgroup
  3. find_server_in_workgroup
  4. remove_server_from_workgroup
  5. create_server_on_workgroup
  6. update_server_ttl
  7. expire_servers
  8. write_this_server_name
  9. write_this_workgroup_name
  10. write_browse_list_entry
  11. write_browse_list

   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-1998
   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 int updatecount = 0;
  26 
  27 /*******************************************************************
  28   Remove all the servers in a work group.
  29   ******************************************************************/
  30 
  31 void remove_all_servers(struct work_record *work)
     /* [<][>][^][v][top][bottom][index][help] */
  32 {
  33         struct server_record *servrec;
  34         struct server_record *nexts;
  35 
  36         for (servrec = work->serverlist; servrec; servrec = nexts) {
  37                 DEBUG(7,("remove_all_servers: Removing server %s\n",servrec->serv.name));
  38                 nexts = servrec->next;
  39 
  40                 if (servrec->prev)
  41                         servrec->prev->next = servrec->next;
  42                 if (servrec->next)
  43                         servrec->next->prev = servrec->prev;
  44 
  45                 if (work->serverlist == servrec)
  46                         work->serverlist = servrec->next;
  47 
  48                 ZERO_STRUCTP(servrec);
  49                 SAFE_FREE(servrec);
  50         }
  51 
  52         work->subnet->work_changed = True;
  53 }
  54 
  55 /***************************************************************************
  56   Add a server into the a workgroup serverlist.
  57   **************************************************************************/
  58 
  59 static void add_server_to_workgroup(struct work_record *work,
     /* [<][>][^][v][top][bottom][index][help] */
  60                              struct server_record *servrec)
  61 {
  62         struct server_record *servrec2;
  63 
  64         if (!work->serverlist) {
  65                 work->serverlist = servrec;
  66                 servrec->prev = NULL;
  67                 servrec->next = NULL;
  68                 return;
  69         }
  70 
  71         for (servrec2 = work->serverlist; servrec2->next; servrec2 = servrec2->next)
  72                 ;
  73 
  74         servrec2->next = servrec;
  75         servrec->next = NULL;
  76         servrec->prev = servrec2;
  77         work->subnet->work_changed = True;
  78 }
  79 
  80 /****************************************************************************
  81   Find a server in a server list.
  82   **************************************************************************/
  83 
  84 struct server_record *find_server_in_workgroup(struct work_record *work, const char *name)
     /* [<][>][^][v][top][bottom][index][help] */
  85 {
  86         struct server_record *ret;
  87   
  88         for (ret = work->serverlist; ret; ret = ret->next) {
  89                 if (strequal(ret->serv.name,name))
  90                         return ret;
  91         }
  92         return NULL;
  93 }
  94 
  95 
  96 /****************************************************************************
  97   Remove a server entry from this workgroup.
  98   ****************************************************************************/
  99 
 100 void remove_server_from_workgroup(struct work_record *work, struct server_record *servrec)
     /* [<][>][^][v][top][bottom][index][help] */
 101 {
 102         if (servrec->prev)
 103                 servrec->prev->next = servrec->next;
 104         if (servrec->next)
 105                 servrec->next->prev = servrec->prev;
 106 
 107         if (work->serverlist == servrec) 
 108                 work->serverlist = servrec->next; 
 109 
 110         ZERO_STRUCTP(servrec);
 111         SAFE_FREE(servrec);
 112         work->subnet->work_changed = True;
 113 }
 114 
 115 /****************************************************************************
 116   Create a server entry on this workgroup.
 117   ****************************************************************************/
 118 
 119 struct server_record *create_server_on_workgroup(struct work_record *work,
     /* [<][>][^][v][top][bottom][index][help] */
 120                                                  const char *name,int servertype, 
 121                                                  int ttl, const char *comment)
 122 {
 123         struct server_record *servrec;
 124   
 125         if (name[0] == '*') {
 126                 DEBUG(7,("create_server_on_workgroup: not adding name starting with '*' (%s)\n",
 127                         name));
 128                 return (NULL);
 129         }
 130   
 131         if(find_server_in_workgroup(work, name) != NULL) {
 132                 DEBUG(0,("create_server_on_workgroup: Server %s already exists on \
 133 workgroup %s. This is a bug.\n", name, work->work_group));
 134                 return NULL;
 135         }
 136   
 137         if((servrec = SMB_MALLOC_P(struct server_record)) == NULL) {
 138                 DEBUG(0,("create_server_entry_on_workgroup: malloc fail !\n"));
 139                 return NULL;
 140         }
 141 
 142         memset((char *)servrec,'\0',sizeof(*servrec));
 143  
 144         servrec->subnet = work->subnet;
 145  
 146         fstrcpy(servrec->serv.name,name);
 147         fstrcpy(servrec->serv.comment,comment);
 148         strupper_m(servrec->serv.name);
 149         servrec->serv.type  = servertype;
 150 
 151         update_server_ttl(servrec, ttl);
 152   
 153         add_server_to_workgroup(work, servrec);
 154       
 155         DEBUG(3,("create_server_on_workgroup: Created server entry %s of type %x (%s) on \
 156 workgroup %s.\n", name,servertype,comment, work->work_group));
 157  
 158         work->subnet->work_changed = True;
 159  
 160         return(servrec);
 161 }
 162 
 163 /*******************************************************************
 164  Update the ttl field of a server record.
 165 *******************************************************************/
 166 
 167 void update_server_ttl(struct server_record *servrec, int ttl)
     /* [<][>][^][v][top][bottom][index][help] */
 168 {
 169         if(ttl > lp_max_ttl())
 170                 ttl = lp_max_ttl();
 171 
 172         if(is_myname(servrec->serv.name))
 173                 servrec->death_time = PERMANENT_TTL;
 174         else
 175                 servrec->death_time = (ttl != PERMANENT_TTL) ? time(NULL)+(ttl*3) : PERMANENT_TTL;
 176 
 177         servrec->subnet->work_changed = True;
 178 }
 179 
 180 /*******************************************************************
 181   Expire old servers in the serverlist. A time of -1 indicates 
 182   everybody dies except those with a death_time of PERMANENT_TTL (which is 0).
 183   This should only be called from expire_workgroups_and_servers().
 184   ******************************************************************/
 185 
 186 void expire_servers(struct work_record *work, time_t t)
     /* [<][>][^][v][top][bottom][index][help] */
 187 {
 188         struct server_record *servrec;
 189         struct server_record *nexts;
 190   
 191         for (servrec = work->serverlist; servrec; servrec = nexts) {
 192                 nexts = servrec->next;
 193 
 194                 if ((servrec->death_time != PERMANENT_TTL) && ((t == -1) || (servrec->death_time < t))) {
 195                         DEBUG(3,("expire_old_servers: Removing timed out server %s\n",servrec->serv.name));
 196                         remove_server_from_workgroup(work, servrec);
 197                         work->subnet->work_changed = True;
 198                 }
 199         }
 200 }
 201 
 202 /*******************************************************************
 203  Decide if we should write out a server record for this server.
 204  We return zero if we should not. Check if we've already written
 205  out this server record from an earlier subnet.
 206 ******************************************************************/
 207 
 208 static uint32 write_this_server_name( struct subnet_record *subrec,
     /* [<][>][^][v][top][bottom][index][help] */
 209                                       struct work_record *work,
 210                                       struct server_record *servrec)
 211 {
 212         struct subnet_record *ssub;
 213         struct work_record *iwork;
 214 
 215         /* Go through all the subnets we have already seen. */
 216         for (ssub = FIRST_SUBNET; ssub && (ssub != subrec); ssub = NEXT_SUBNET_INCLUDING_UNICAST(ssub)) {
 217                 for(iwork = ssub->workgrouplist; iwork; iwork = iwork->next) {
 218                         if(find_server_in_workgroup( iwork, servrec->serv.name) != NULL) {
 219                                 /*
 220                                  * We have already written out this server record, don't
 221                                  * do it again. This gives precedence to servers we have seen
 222                                  * on the broadcast subnets over servers that may have been
 223                                  * added via a sync on the unicast_subet.
 224                                  *
 225                                  * The correct way to do this is to have a serverlist file
 226                                  * per subnet - this means changes to smbd as well. I may
 227                                  * add this at a later date (JRA).
 228                                  */
 229 
 230                                 return 0;
 231                         }
 232                 }
 233         }
 234 
 235         return servrec->serv.type;
 236 }
 237 
 238 /*******************************************************************
 239  Decide if we should write out a workgroup record for this workgroup.
 240  We return zero if we should not. Don't write out lp_workgroup() (we've
 241  already done it) and also don't write out a second workgroup record
 242  on the unicast subnet that we've already written out on one of the
 243  broadcast subnets.
 244 ******************************************************************/
 245 
 246 static uint32 write_this_workgroup_name( struct subnet_record *subrec, 
     /* [<][>][^][v][top][bottom][index][help] */
 247                                          struct work_record *work)
 248 {
 249         struct subnet_record *ssub;
 250 
 251         if(strequal(lp_workgroup(), work->work_group))
 252                 return 0;
 253 
 254         /* This is a workgroup we have seen on a broadcast subnet. All
 255                 these have the same type. */
 256 
 257         if(subrec != unicast_subnet)
 258                 return (SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY);
 259 
 260         for(ssub = FIRST_SUBNET; ssub;  ssub = NEXT_SUBNET_EXCLUDING_UNICAST(ssub)) {
 261                 /* This is the unicast subnet so check if we've already written out
 262                         this subnet when we passed over the broadcast subnets. */
 263 
 264                 if(find_workgroup_on_subnet( ssub, work->work_group) != NULL)
 265                         return 0;
 266         }
 267 
 268         /* All workgroups on the unicast subnet (except our own, which we
 269                 have already written out) cannot be local. */
 270 
 271         return (SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT);
 272 }
 273 
 274 /*******************************************************************
 275   Write out the browse.dat file.
 276   ******************************************************************/
 277 
 278 void write_browse_list_entry(XFILE *fp, const char *name, uint32 rec_type,
     /* [<][>][^][v][top][bottom][index][help] */
 279                 const char *local_master_browser_name, const char *description)
 280 {
 281         fstring tmp;
 282 
 283         slprintf(tmp,sizeof(tmp)-1, "\"%s\"", name);
 284         x_fprintf(fp, "%-25s ", tmp);
 285         x_fprintf(fp, "%08x ", rec_type);
 286         slprintf(tmp, sizeof(tmp)-1, "\"%s\" ", local_master_browser_name);
 287         x_fprintf(fp, "%-30s", tmp);
 288         x_fprintf(fp, "\"%s\"\n", description);
 289 }
 290 
 291 void write_browse_list(time_t t, bool force_write)
     /* [<][>][^][v][top][bottom][index][help] */
 292 {
 293         struct subnet_record *subrec;
 294         struct work_record *work;
 295         struct server_record *servrec;
 296         char *fname;
 297         char *fnamenew;
 298         uint32 stype;
 299         int i;
 300         XFILE *fp;
 301         bool list_changed = force_write;
 302         static time_t lasttime = 0;
 303         TALLOC_CTX *ctx = talloc_tos();
 304 
 305         /* Always dump if we're being told to by a signal. */
 306         if(force_write == False) {
 307                 if (!lasttime)
 308                         lasttime = t;
 309                 if (t - lasttime < 5)
 310                         return;
 311         }
 312 
 313         lasttime = t;
 314 
 315         dump_workgroups(force_write);
 316 
 317         for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
 318                 if(subrec->work_changed) {
 319                         list_changed = True;
 320                         break;
 321                 }
 322         }
 323 
 324         if(!list_changed)
 325                 return;
 326 
 327         updatecount++;
 328 
 329         fname = cache_path(SERVER_LIST);
 330         if (!fname) {
 331                 return;
 332         }
 333         fnamenew = talloc_asprintf(ctx, "%s.",
 334                                 fname);
 335         if (!fnamenew) {
 336                 return;
 337         }
 338 
 339         fp = x_fopen(fnamenew,O_WRONLY|O_CREAT|O_TRUNC, 0644);
 340 
 341         if (!fp) {
 342                 DEBUG(0,("write_browse_list: Can't open file %s. Error was %s\n",
 343                         fnamenew,strerror(errno)));
 344                 return;
 345         }
 346 
 347         /*
 348          * Write out a record for our workgroup. Use the record from the first
 349          * subnet.
 350          */
 351 
 352         if((work = find_workgroup_on_subnet(FIRST_SUBNET, lp_workgroup())) == NULL) { 
 353                 DEBUG(0,("write_browse_list: Fatal error - cannot find my workgroup %s\n",
 354                         lp_workgroup()));
 355                 x_fclose(fp);
 356                 return;
 357         }
 358 
 359         write_browse_list_entry(fp, work->work_group,
 360                 SV_TYPE_DOMAIN_ENUM|SV_TYPE_NT|SV_TYPE_LOCAL_LIST_ONLY,
 361                 work->local_master_browser_name, work->work_group);
 362 
 363         /*
 364          * We need to do something special for our own names.
 365          * This is due to the fact that we may be a local master browser on
 366          * one of our broadcast subnets, and a domain master on the unicast
 367          * subnet. We iterate over the subnets and only write out the name
 368          * once.
 369          */
 370 
 371         for (i=0; my_netbios_names(i); i++) {
 372                 stype = 0;
 373                 for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) {
 374                         if((work = find_workgroup_on_subnet( subrec, lp_workgroup() )) == NULL)
 375                                 continue;
 376                         if((servrec = find_server_in_workgroup( work, my_netbios_names(i))) == NULL)
 377                                 continue;
 378 
 379                         stype |= servrec->serv.type;
 380                 }
 381 
 382                 /* Output server details, plus what workgroup they're in. */
 383                 write_browse_list_entry(fp, my_netbios_names(i), stype,
 384                         string_truncate(lp_serverstring(), MAX_SERVER_STRING_LENGTH), lp_workgroup());
 385         }
 386 
 387         for (subrec = FIRST_SUBNET; subrec ; subrec = NEXT_SUBNET_INCLUDING_UNICAST(subrec)) { 
 388                 subrec->work_changed = False;
 389 
 390                 for (work = subrec->workgrouplist; work ; work = work->next) {
 391                         /* Write out a workgroup record for a workgroup. */
 392                         uint32 wg_type = write_this_workgroup_name( subrec, work);
 393 
 394                         if(wg_type) {
 395                                 write_browse_list_entry(fp, work->work_group, wg_type,
 396                                                 work->local_master_browser_name,
 397                                                 work->work_group);
 398                         }
 399 
 400                         /* Now write out any server records a workgroup may have. */
 401 
 402                         for (servrec = work->serverlist; servrec ; servrec = servrec->next) {
 403                                 uint32 serv_type;
 404 
 405                                 /* We have already written our names here. */
 406                                 if(is_myname(servrec->serv.name))
 407                                         continue;
 408 
 409                                 serv_type = write_this_server_name(subrec, work, servrec);
 410                                 if(serv_type) {
 411                                         /* Output server details, plus what workgroup they're in. */
 412                                         write_browse_list_entry(fp, servrec->serv.name, serv_type,
 413                                                 servrec->serv.comment, work->work_group);
 414                                 }
 415                         }
 416                 }
 417         }
 418 
 419         x_fclose(fp);
 420         unlink(fname);
 421         chmod(fnamenew,0644);
 422         rename(fnamenew,fname);
 423         DEBUG(3,("write_browse_list: Wrote browse list into file %s\n",fname));
 424 }

/* [<][>][^][v][top][bottom][index][help] */