Removed global_myworkgroup, global_myname, global_myscope. Added liberal
[ira/wip.git] / source3 / lib / wins_srv.c
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
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 /*
25   this is pretty much a complete rewrite of the earlier code. The main
26   aim of the rewrite is to add support for having multiple wins server
27   lists, so Samba can register with multiple groups of wins servers
28   and each group has a failover list of wins servers.
29
30   Central to the way it all works is the idea of a wins server
31   'tag'. A wins tag is a label for a group of wins servers. For
32   example if you use
33
34       wins server = fred:192.168.2.10 mary:192.168.3.199 fred:192.168.2.61
35
36   then you would have two groups of wins servers, one tagged with the
37   name 'fred' and the other with the name 'mary'. I would usually
38   recommend using interface names instead of 'fred' and 'mary' but
39   they can be any alpha string.
40
41   Now, how does it all work. Well, nmbd needs to register each of its
42   IPs with each of its names once with each group of wins servers. So
43   it tries registering with the first one mentioned in the list, then
44   if that fails it marks that WINS server dead and moves onto the next
45   one. 
46
47   In the client code things are a bit different. As each of the groups
48   of wins servers is a separate name space we need to try each of the
49   groups until we either succeed or we run out of wins servers to
50   try. If we get a negative response from a wins server then that
51   means the name doesn't exist in that group, so we give up on that
52   group and move to the next group. If we don't get a response at all
53   then maybe the wins server is down, in which case we need to
54   failover to the next one for that group.
55
56   confused yet? (tridge)
57 */
58
59
60 /* how long a server is marked dead for */
61 #define DEATH_TIME 600
62
63 /* a list of wins server that are marked dead from the point of view
64    of a given source address. We keep a separate dead list for each src address
65    to cope with multiple interfaces that are not routable to each other
66   */
67 static struct wins_dead {
68         struct in_addr dest_ip;
69         struct in_addr src_ip;
70         time_t revival; /* when it will be revived */
71         struct wins_dead *next, *prev;
72 } *dead_servers;
73
74 /* an internal convenience structure for an IP with a short string tag
75    attached */
76 struct tagged_ip {
77         fstring tag;
78         struct in_addr ip;
79 };
80
81 /*
82   see if an ip is on the dead list
83 */
84 BOOL wins_srv_is_dead(struct in_addr wins_ip, struct in_addr src_ip)
85 {
86         struct wins_dead *d;
87         for (d=dead_servers; d; d=d->next) {
88                 if (ip_equal(wins_ip, d->dest_ip) && ip_equal(src_ip, d->src_ip)) {
89                         /* it might be due for revival */
90                         if (d->revival <= time(NULL)) {
91                                 fstring src_name;
92                                 fstrcpy(src_name, inet_ntoa(src_ip));
93                                 DEBUG(4,("Reviving wins server %s for source %s\n", 
94                                          inet_ntoa(wins_ip), src_name));
95                                 DLIST_REMOVE(dead_servers, d);
96                                 free(d);
97                                 return False;
98                         }
99                         return True;
100                 }
101         }
102         return False;
103 }
104
105
106 /*
107   mark a wins server as being alive (for the moment)
108 */
109 void wins_srv_alive(struct in_addr wins_ip, struct in_addr src_ip)
110 {
111         struct wins_dead *d;
112         for (d=dead_servers; d; d=d->next) {
113                 if (ip_equal(wins_ip, d->dest_ip) && ip_equal(src_ip, d->src_ip)) {
114                         fstring src_name;
115                         fstrcpy(src_name, inet_ntoa(src_ip));
116                         DEBUG(4,("Reviving wins server %s for source %s\n", 
117                                  inet_ntoa(wins_ip), src_name));
118                         DLIST_REMOVE(dead_servers, d);
119                         return;
120                 }
121         }
122 }
123
124
125 /*
126   mark a wins server as temporarily dead
127 */
128 void wins_srv_died(struct in_addr wins_ip, struct in_addr src_ip)
129 {
130         struct wins_dead *d;
131         fstring src_name;
132
133         if (is_zero_ip(wins_ip) || wins_srv_is_dead(wins_ip, src_ip)) {
134                 return;
135         }
136
137         d = (struct wins_dead *)malloc(sizeof(*d));
138         if (!d) return;
139
140         d->dest_ip = wins_ip;
141         d->src_ip = src_ip;
142         d->revival = time(NULL) + DEATH_TIME;
143
144         fstrcpy(src_name, inet_ntoa(src_ip));
145
146         DEBUG(4,("Marking wins server %s dead for %u seconds from source %s\n", 
147                  inet_ntoa(wins_ip), DEATH_TIME, src_name));
148
149         DLIST_ADD(dead_servers, d);
150 }
151
152 /*
153   return the total number of wins servers, dead or not
154 */
155 unsigned wins_srv_count(void)
156 {
157         const char **list;
158         int count = 0;
159
160         if (lp_wins_support()) {
161                 /* simple - just talk to ourselves */
162                 return 1;
163         }
164
165         list = lp_wins_server_list();
166         for (count=0; list && list[count]; count++)
167                 /* nop */ ;
168
169         return count;
170 }
171
172 /*
173   parse an IP string that might be in tagged format
174   the result is a tagged_ip structure containing the tag
175   and the ip in in_addr format. If there is no tag then
176   use the tag '*'
177 */
178 static void parse_ip(struct tagged_ip *ip, const char *str)
179 {
180         char *s = strchr(str, ':');
181         if (!s) {
182                 fstrcpy(ip->tag, "*");
183                 ip->ip = *interpret_addr2(str);
184                 return;
185         } 
186
187         ip->ip = *interpret_addr2(s+1);
188         fstrcpy(ip->tag, str);
189         s = strchr(ip->tag, ':');
190         if (s) *s = 0;
191 }
192
193
194
195 /*
196   return the list of wins server tags. A 'tag' is used to distinguish
197   wins server as either belonging to the same name space or a separate
198   name space. Usually you would setup your 'wins server' option to
199   list one or more wins server per interface and use the interface
200   name as your tag, but you are free to use any tag you like.
201 */
202 char **wins_srv_tags(void)
203 {
204         char **ret = NULL;
205         int count=0, i, j;
206         const char **list;
207
208         if (lp_wins_support()) {
209                 /* give the caller something to chew on. This makes
210                    the rest of the logic simpler (ie. less special cases) */
211                 ret = (char **)malloc(sizeof(char *)*2);
212                 if (!ret) return NULL;
213                 ret[0] = strdup("*");
214                 ret[1] = NULL;
215                 return ret;
216         }
217
218         list = lp_wins_server_list();
219         if (!list)
220                 return NULL;
221
222         /* yes, this is O(n^2) but n is very small */
223         for (i=0;list[i];i++) {
224                 struct tagged_ip t_ip;
225                 
226                 parse_ip(&t_ip, list[i]);
227
228                 /* see if we already have it */
229                 for (j=0;j<count;j++) {
230                         if (strcmp(ret[j], t_ip.tag) == 0) {
231                                 break;
232                         }
233                 }
234
235                 if (j != count) {
236                         /* we already have it. Move along */
237                         continue;
238                 }
239
240                 /* add it to the list */
241                 ret = (char **)Realloc(ret, (count+2) * sizeof(char *));
242                 ret[count] = strdup(t_ip.tag);
243                 if (!ret[count]) break;
244                 count++;
245         }
246
247         if (count) {
248                 /* make sure we null terminate */
249                 ret[count] = NULL;
250         }
251
252         return ret;
253 }
254
255 /* free a list of wins server tags given by wins_srv_tags */
256 void wins_srv_tags_free(char **list)
257 {
258         int i;
259         if (!list) return;
260         for (i=0; list[i]; i++) {
261                 free(list[i]);
262         }
263         free(list);
264 }
265
266
267 /*
268   return the IP of the currently active wins server for the given tag,
269   or the zero IP otherwise
270 */
271 struct in_addr wins_srv_ip_tag(const char *tag, struct in_addr src_ip)
272 {
273         const char **list;
274         int i;
275         struct tagged_ip t_ip;
276
277         /* if we are a wins server then we always just talk to ourselves */
278         if (lp_wins_support()) {
279                 extern struct in_addr loopback_ip;
280                 return loopback_ip;
281         }
282
283         list = lp_wins_server_list();
284         if (!list || !list[0]) {
285                 struct in_addr ip;
286                 zero_ip(&ip);
287                 return ip;
288         }
289
290         /* find the first live one for this tag */
291         for (i=0; list[i]; i++) {
292                 parse_ip(&t_ip, list[i]);
293                 if (strcmp(tag, t_ip.tag) != 0) {
294                         /* not for the right tag. Move along */
295                         continue;
296                 }
297                 if (!wins_srv_is_dead(t_ip.ip, src_ip)) {
298                         fstring src_name;
299                         fstrcpy(src_name, inet_ntoa(src_ip));
300                         DEBUG(6,("Current wins server for tag '%s' with source %s is %s\n", 
301                                  tag, 
302                                  src_name,
303                                  inet_ntoa(t_ip.ip)));
304                         return t_ip.ip;
305                 }
306         }
307         
308         /* they're all dead - try the first one until they revive */
309         for (i=0; list[i]; i++) {
310                 parse_ip(&t_ip, list[i]);
311                 if (strcmp(tag, t_ip.tag) != 0) {
312                         continue;
313                 }
314                 return t_ip.ip;
315         }
316
317         /* this can't happen?? */
318         zero_ip(&t_ip.ip);
319         return t_ip.ip;
320 }
321
322
323 /*
324   return a count of the number of IPs for a particular tag, including
325   dead ones
326 */
327 unsigned wins_srv_count_tag(const char *tag)
328 {
329         const char **list;
330         int i, count=0;
331
332         /* if we are a wins server then we always just talk to ourselves */
333         if (lp_wins_support()) {
334                 return 1;
335         }
336
337         list = lp_wins_server_list();
338         if (!list || !list[0]) {
339                 return 0;
340         }
341
342         /* find the first live one for this tag */
343         for (i=0; list[i]; i++) {
344                 struct tagged_ip t_ip;
345                 parse_ip(&t_ip, list[i]);
346                 if (strcmp(tag, t_ip.tag) == 0) {
347                         count++;
348                 }
349         }
350
351         return count;
352 }