LCOV - code coverage report
Current view: top level - source3/lib - wins_srv.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 64 160 40.0 %
Date: 2024-04-21 15:09:00 Functions: 7 11 63.6 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Samba wins server helper functions
       4             :    Copyright (C) Andrew Tridgell 1992-2002
       5             :    Copyright (C) Christopher R. Hertel 2000
       6             :    Copyright (C) Tim Potter 2003
       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             : #include "includes.h"
      23             : #include "lib/gencache.h"
      24             : #include "lib/util/string_wrappers.h"
      25             : 
      26             : /*
      27             :   This is pretty much a complete rewrite of the earlier code. The main
      28             :   aim of the rewrite is to add support for having multiple wins server
      29             :   lists, so Samba can register with multiple groups of wins servers
      30             :   and each group has a failover list of wins servers.
      31             : 
      32             :   Central to the way it all works is the idea of a wins server
      33             :   'tag'. A wins tag is a label for a group of wins servers. For
      34             :   example if you use
      35             : 
      36             :       wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
      37             : 
      38             :   then you would have two groups of wins servers, one tagged with the
      39             :   name 'fred' and the other with the name 'mary'. I would usually
      40             :   recommend using interface names instead of 'fred' and 'mary' but
      41             :   they can be any alpha string.
      42             : 
      43             :   Now, how does it all work. Well, nmbd needs to register each of its
      44             :   IPs with each of its names once with each group of wins servers. So
      45             :   it tries registering with the first one mentioned in the list, then
      46             :   if that fails it marks that WINS server dead and moves onto the next
      47             :   one. 
      48             : 
      49             :   In the client code things are a bit different. As each of the groups
      50             :   of wins servers is a separate name space we need to try each of the
      51             :   groups until we either succeed or we run out of wins servers to
      52             :   try. If we get a negative response from a wins server then that
      53             :   means the name doesn't exist in that group, so we give up on that
      54             :   group and move to the next group. If we don't get a response at all
      55             :   then maybe the wins server is down, in which case we need to
      56             :   failover to the next one for that group.
      57             : 
      58             :   confused yet? (tridge)
      59             : */
      60             : 
      61             : /* how long a server is marked dead for */
      62             : #define DEATH_TIME 600
      63             : 
      64             : /* The list of dead wins servers is stored in gencache.tdb.  Each server is
      65             :    marked dead from the point of view of a given source address. We keep a 
      66             :    separate dead list for each src address to cope with multiple interfaces 
      67             :    that are not routable to each other.
      68             :   */
      69             : 
      70             : #define WINS_SRV_FMT "WINS_SRV_DEAD/%s,%s" /* wins_ip,src_ip */
      71             : 
      72          37 : static char *wins_srv_keystr(struct in_addr wins_ip, struct in_addr src_ip)
      73             : {
      74          37 :         char *keystr = NULL, *wins_ip_addr = NULL, *src_ip_addr = NULL;
      75             : 
      76          37 :         wins_ip_addr = SMB_STRDUP(inet_ntoa(wins_ip));
      77          37 :         src_ip_addr = SMB_STRDUP(inet_ntoa(src_ip));
      78             : 
      79          37 :         if ( !wins_ip_addr || !src_ip_addr ) {
      80           0 :                 DEBUG(0,("wins_srv_keystr: malloc error\n"));
      81           0 :                 goto done;
      82             :         }
      83             : 
      84          37 :         if (asprintf(&keystr, WINS_SRV_FMT, wins_ip_addr, src_ip_addr) == -1) {
      85           0 :                 DEBUG(0, (": ns_srv_keystr: malloc error for key string\n"));
      86             :         }
      87             : 
      88          37 : done:
      89          37 :         SAFE_FREE(wins_ip_addr);
      90          37 :         SAFE_FREE(src_ip_addr);
      91             : 
      92          37 :         return keystr;
      93             : }
      94             : 
      95             : /*
      96             :   see if an ip is on the dead list
      97             : */
      98             : 
      99          37 : bool wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip)
     100             : {
     101          37 :         char *keystr = wins_srv_keystr(wins_ip, src_ip);
     102           0 :         bool result;
     103             : 
     104             :         /* If the key exists then the WINS server has been marked as dead */
     105             : 
     106          37 :         result = gencache_get(keystr, NULL, NULL, NULL);
     107          37 :         SAFE_FREE(keystr);
     108             : 
     109          37 :         DEBUG(4, ("wins_srv_is_dead: %s is %s\n", inet_ntoa(wins_ip),
     110             :                   result ? "dead" : "alive"));
     111             : 
     112          37 :         return result;
     113             : }
     114             : 
     115             : 
     116             : /*
     117             :   mark a wins server as being alive (for the moment)
     118             : */
     119           0 : void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip)
     120             : {
     121           0 :         char *keystr = wins_srv_keystr(wins_ip, src_ip);
     122             : 
     123           0 :         gencache_del(keystr);
     124           0 :         SAFE_FREE(keystr);
     125             : 
     126           0 :         DEBUG(4, ("wins_srv_alive: marking wins server %s alive\n", 
     127             :                   inet_ntoa(wins_ip)));
     128           0 : }
     129             : 
     130             : /*
     131             :   mark a wins server as temporarily dead
     132             : */
     133           0 : void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip)
     134             : {
     135           0 :         char *keystr;
     136             : 
     137           0 :         if (is_zero_ip_v4(wins_ip) || wins_srv_is_dead(wins_ip, src_ip))
     138           0 :                 return;
     139             : 
     140           0 :         keystr = wins_srv_keystr(wins_ip, src_ip);
     141             : 
     142           0 :         gencache_set(keystr, "DOWN", time(NULL) + DEATH_TIME);
     143             : 
     144           0 :         SAFE_FREE(keystr);
     145             : 
     146           0 :         DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n",
     147             :                  inet_ntoa(wins_ip), DEATH_TIME, inet_ntoa(src_ip)));
     148             : }
     149             : 
     150             : /*
     151             :   return the total number of wins servers, dead or not
     152             : */
     153      105233 : unsigned wins_srv_count(void)
     154             : {
     155           0 :         const char **list;
     156      105233 :         int count = 0;
     157             : 
     158      105233 :         if (lp_we_are_a_wins_server()) {
     159             :                 /* simple - just talk to ourselves */
     160          40 :                 return 1;
     161             :         }
     162             : 
     163      105193 :         list = lp_wins_server_list();
     164      105193 :         for (count=0; list && list[count]; count++)
     165             :                 /* nop */ ;
     166             : 
     167      105193 :         return count;
     168             : }
     169             : 
     170             : /* an internal convenience structure for an IP with a short string tag
     171             :    attached */
     172             : struct tagged_ip {
     173             :         fstring tag;
     174             :         struct in_addr ip;
     175             : };
     176             : 
     177             : /*
     178             :   parse an IP string that might be in tagged format
     179             :   the result is a tagged_ip structure containing the tag
     180             :   and the ip in in_addr format. If there is no tag then
     181             :   use the tag '*'
     182             : */
     183          74 : static void parse_ip(struct tagged_ip *ip, const char *str)
     184             : {
     185          74 :         char *s = strchr(str, ':');
     186          74 :         if (!s) {
     187          74 :                 fstrcpy(ip->tag, "*");
     188          74 :                 ip->ip = interpret_addr2(str);
     189          74 :                 return;
     190             :         } 
     191             : 
     192           0 :         ip->ip = interpret_addr2(s+1);
     193           0 :         fstrcpy(ip->tag, str);
     194           0 :         s = strchr(ip->tag, ':');
     195           0 :         if (s) {
     196           0 :                 *s = 0;
     197             :         }
     198             : }
     199             : 
     200             : 
     201             : 
     202             : /*
     203             :   return the list of wins server tags. A 'tag' is used to distinguish
     204             :   wins server as either belonging to the same name space or a separate
     205             :   name space. Usually you would setup your 'wins server' option to
     206             :   list one or more wins server per interface and use the interface
     207             :   name as your tag, but you are free to use any tag you like.
     208             : */
     209          40 : char **wins_srv_tags(void)
     210             : {
     211          40 :         char **ret = NULL;
     212          40 :         unsigned int count=0, i, j;
     213           0 :         const char **list;
     214             : 
     215          40 :         if (lp_we_are_a_wins_server()) {
     216             :                 /* give the caller something to chew on. This makes
     217             :                    the rest of the logic simpler (ie. less special cases) */
     218          40 :                 ret = SMB_MALLOC_ARRAY(char *, 2);
     219          40 :                 if (!ret) return NULL;
     220          40 :                 ret[0] = SMB_STRDUP("*");
     221          40 :                 ret[1] = NULL;
     222          40 :                 return ret;
     223             :         }
     224             : 
     225           0 :         list = lp_wins_server_list();
     226           0 :         if (!list)
     227           0 :                 return NULL;
     228             : 
     229             :         /* yes, this is O(n^2) but n is very small */
     230           0 :         for (i=0;list[i];i++) {
     231           0 :                 struct tagged_ip t_ip;
     232             : 
     233           0 :                 parse_ip(&t_ip, list[i]);
     234             : 
     235             :                 /* see if we already have it */
     236           0 :                 for (j=0;j<count;j++) {
     237           0 :                         if (strcmp(ret[j], t_ip.tag) == 0) {
     238           0 :                                 break;
     239             :                         }
     240             :                 }
     241             : 
     242           0 :                 if (j != count) {
     243             :                         /* we already have it. Move along */
     244           0 :                         continue;
     245             :                 }
     246             : 
     247             :                 /* add it to the list */
     248           0 :                 ret = SMB_REALLOC_ARRAY(ret, char *, count+2);
     249           0 :                 if (!ret) {
     250           0 :                         return NULL;
     251             :                 }
     252           0 :                 ret[count] = SMB_STRDUP(t_ip.tag);
     253           0 :                 if (!ret[count]) break;
     254           0 :                 count++;
     255             :         }
     256             : 
     257           0 :         if (count) {
     258             :                 /* make sure we null terminate */
     259           0 :                 ret[count] = NULL;
     260             :         }
     261             : 
     262           0 :         return ret;
     263             : }
     264             : 
     265             : /* free a list of wins server tags given by wins_srv_tags */
     266         409 : void wins_srv_tags_free(char **list)
     267             : {
     268           0 :         int i;
     269         409 :         if (!list) return;
     270          80 :         for (i=0; list[i]; i++) {
     271          40 :                 free(list[i]);
     272             :         }
     273          40 :         free(list);
     274             : }
     275             : 
     276             : 
     277             : /*
     278             :   return the IP of the currently active wins server for the given tag,
     279             :   or the zero IP otherwise
     280             : */
     281           0 : struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip)
     282             : {
     283           0 :         const char **list;
     284           0 :         int i;
     285           0 :         struct tagged_ip t_ip;
     286             : 
     287             :         /* if we are a wins server then we always just talk to ourselves */
     288           0 :         if (lp_we_are_a_wins_server()) {
     289           0 :                 struct in_addr loopback_ip;
     290           0 :                 loopback_ip.s_addr = htonl(INADDR_LOOPBACK);
     291           0 :                 return loopback_ip;
     292             :         }
     293             : 
     294           0 :         list = lp_wins_server_list();
     295           0 :         if (!list || !list[0]) {
     296           0 :                 struct in_addr ip;
     297           0 :                 zero_ip_v4(&ip);
     298           0 :                 return ip;
     299             :         }
     300             : 
     301             :         /* find the first live one for this tag */
     302           0 :         for (i=0; list[i]; i++) {
     303           0 :                 parse_ip(&t_ip, list[i]);
     304           0 :                 if (strcmp(tag, t_ip.tag) != 0) {
     305             :                         /* not for the right tag. Move along */
     306           0 :                         continue;
     307             :                 }
     308           0 :                 if (!wins_srv_is_dead(t_ip.ip, src_ip)) {
     309           0 :                         fstring src_name;
     310           0 :                         fstrcpy(src_name, inet_ntoa(src_ip));
     311           0 :                         DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n", 
     312             :                                  tag, 
     313             :                                  src_name,
     314             :                                  inet_ntoa(t_ip.ip)));
     315           0 :                         return t_ip.ip;
     316             :                 }
     317             :         }
     318             : 
     319             :         /* they're all dead - try the first one until they revive */
     320           0 :         for (i=0; list[i]; i++) {
     321           0 :                 parse_ip(&t_ip, list[i]);
     322           0 :                 if (strcmp(tag, t_ip.tag) != 0) {
     323           0 :                         continue;
     324             :                 }
     325           0 :                 return t_ip.ip;
     326             :         }
     327             : 
     328             :         /* this can't happen?? */
     329           0 :         zero_ip_v4(&t_ip.ip);
     330           0 :         return t_ip.ip;
     331             : }
     332             : 
     333          40 : bool wins_server_tag_ips(const char *tag, TALLOC_CTX *mem_ctx,
     334             :                          struct in_addr **pservers, size_t *pnum_servers)
     335             : {
     336           0 :         const char **list;
     337           0 :         size_t i, num_servers;
     338           0 :         struct in_addr *servers;
     339             : 
     340          40 :         list = lp_wins_server_list();
     341          40 :         if ((list == NULL) || (list[0] == NULL)) {
     342           3 :                 return false;
     343             :         }
     344             : 
     345          37 :         num_servers = 0;
     346             : 
     347          74 :         for (i=0; list[i] != NULL; i++) {
     348           0 :                 struct tagged_ip t_ip;
     349          37 :                 parse_ip(&t_ip, list[i]);
     350          37 :                 if (strcmp(tag, t_ip.tag) == 0) {
     351             :                         /* Wrap check. */
     352          37 :                         if (num_servers + 1 < num_servers) {
     353           0 :                                 return false;
     354             :                         }
     355          37 :                         num_servers += 1;
     356             :                 }
     357             :         }
     358             : 
     359          37 :         servers = talloc_array(mem_ctx, struct in_addr, num_servers);
     360          37 :         if (servers == NULL) {
     361           0 :                 return false;
     362             :         }
     363             : 
     364          37 :         num_servers = 0;
     365             : 
     366          74 :         for (i=0; list[i] != NULL; i++) {
     367           0 :                 struct tagged_ip t_ip;
     368          37 :                 parse_ip(&t_ip, list[i]);
     369          37 :                 if (strcmp(tag, t_ip.tag) == 0) {
     370          37 :                         servers[num_servers] = t_ip.ip;
     371          37 :                         num_servers += 1;
     372             :                 }
     373             :         }
     374          37 :         *pnum_servers = num_servers;
     375          37 :         *pservers = servers;
     376          37 :         return true;
     377             : }
     378             : 
     379             : 
     380             : /*
     381             :   return a count of the number of IPs for a particular tag, including
     382             :   dead ones
     383             : */
     384           0 : unsigned wins_srv_count_tag(const char *tag)
     385             : {
     386           0 :         const char **list;
     387           0 :         int i, count=0;
     388             : 
     389             :         /* if we are a wins server then we always just talk to ourselves */
     390           0 :         if (lp_we_are_a_wins_server()) {
     391           0 :                 return 1;
     392             :         }
     393             : 
     394           0 :         list = lp_wins_server_list();
     395           0 :         if (!list || !list[0]) {
     396           0 :                 return 0;
     397             :         }
     398             : 
     399             :         /* find the first live one for this tag */
     400           0 :         for (i=0; list[i]; i++) {
     401           0 :                 struct tagged_ip t_ip;
     402           0 :                 parse_ip(&t_ip, list[i]);
     403           0 :                 if (strcmp(tag, t_ip.tag) == 0) {
     404           0 :                         count++;
     405             :                 }
     406             :         }
     407             : 
     408           0 :         return count;
     409             : }

Generated by: LCOV version 1.14