namedbname.c: Fixed *nasty* bug that caused nmbd to spin and eat memory
[kai/samba.git] / source3 / nameresp.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    NBT netbios library routines
5    Copyright (C) Andrew Tridgell 1994-1997
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    Module name: nameresp.c
22
23 */
24
25 #include "includes.h"
26
27 extern int ClientNMB;
28 extern int ClientDGRAM;
29
30 extern struct subnet_record *subnetlist;
31
32 extern int DEBUGLEVEL;
33
34 extern pstring scope;
35 extern struct in_addr ipzero;
36 extern struct in_addr wins_ip;
37
38
39 /***************************************************************************
40   deals with an entry before it dies
41   **************************************************************************/
42 static void dead_netbios_entry(struct subnet_record *d,
43                                 struct response_record *n)
44 {
45   DEBUG(3,("Removing dead netbios entry for %s %s (num_msgs=%d)\n",
46            inet_ntoa(n->send_ip), namestr(&n->name), n->num_msgs));
47
48   debug_state_type(n->state);
49
50   switch (n->state)
51   {
52     case NAME_QUERY_CONFIRM:
53     {
54       if (!lp_wins_support()) return; /* only if we're a WINS server */
55       
56       if (n->num_msgs == 0)
57         {
58           /* oops. name query had no response. check that the name is
59              unique and then remove it from our WINS database */
60           
61           /* IMPORTANT: see query_refresh_names() */
62           
63           if ((!NAME_GROUP(n->nb_flags)))
64             {
65               struct subnet_record *d1 = wins_subnet;
66               if (d1)
67                 {
68                   /* remove the name that had been registered with us,
69                      and we're now getting no response when challenging.
70                      see rfc1001.txt 15.5.2
71                      */
72                   remove_netbios_name(d1, n->name.name, n->name.name_type,
73                                       REGISTER, n->send_ip);
74                 }
75             }
76         }
77       break;
78     }
79     
80   case NAME_QUERY_MST_CHK:
81     {
82       /* if no response received, the master browser must have gone
83          down on that subnet, without telling anyone. */
84       
85       /* IMPORTANT: see response_netbios_packet() */
86       
87       if (n->num_msgs == 0)
88         browser_gone(n->name.name, n->send_ip);
89       break;
90     }
91   
92   case NAME_RELEASE:
93     {
94       /* if no response received, it must be OK for us to release the
95          name. nobody objected (including a potentially dead or deaf
96          WINS server) */
97       
98       /* IMPORTANT: see response_name_release() */
99       
100       if (ismyip(n->send_ip))
101         {
102           name_unregister_work(d,n->name.name,n->name.name_type);
103         }
104       if (!n->bcast && n->num_msgs == 0)
105         {
106           DEBUG(0,("WINS server did not respond to name release!\n"));
107           /* XXXX whoops. we have problems. must deal with this */
108         }
109       break;
110     }
111   
112   case NAME_REGISTER_CHALLENGE:
113     {
114       /* name challenge: no reply. we can reply to the person that
115          wanted the unique name and tell them that they can have it
116          */
117       
118       add_name_respond(d,n->fd,d->myip, n->response_id ,&n->name,
119                        n->nb_flags, GET_TTL(0),
120                        n->reply_to_ip, False, n->reply_to_ip);
121       
122       if (!n->bcast && n->num_msgs == 0)
123         {
124           DEBUG(1,("WINS server did not respond to name registration!\n"));
125           /* XXXX whoops. we have problems. must deal with this */
126         }
127       break;
128     }
129   
130   case NAME_REGISTER:
131     {
132       /* if no response received, and we are using a broadcast registration
133          method, it must be OK for us to register the name: nobody objected 
134          on that subnet. if we are using a WINS server, then the WINS
135          server must be dead or deaf.
136          */
137       if (n->num_msgs == 0)
138         {
139           if (n->bcast)
140             {
141               /* broadcast method: implicit acceptance of the name registration
142                  by not receiving any objections. */
143               
144               /* IMPORTANT: see response_name_reg() */
145               
146               name_register_work(d,n->name.name,n->name.name_type,
147                                  n->nb_flags, n->ttl, n->reply_to_ip, n->bcast);
148             }
149           else
150             {
151               /* received no response. rfc1001.txt states that after retrying,
152                  we should assume the WINS server is dead, and fall back to
153                  broadcasting (see bits about M nodes: can't find any right
154                  now) */
155               
156               DEBUG(1,("WINS server did not respond to name registration!\n"));
157               /* XXXX whoops. we have problems. must deal with this */
158             }
159         }
160       break;
161     }
162   
163   case NAME_QUERY_DOMAIN:
164     {
165       /* if no response was received, there is no domain controller for
166          this DOMAIN registered within WINS.  it's ok for us to register
167          the DOMAIN<1b> name.
168          */
169       
170       if (n->num_msgs == 0)
171         {
172           struct work_record *work = find_workgroupstruct(d,n->name.name,False);
173           if (work && d)
174             {
175               become_domain_master(d,work);
176             }
177         }
178       else
179         {
180           DEBUG(0, ("ERROR: nmbd configured as domain master and one already exitsts !!!\n"));
181           exit(1);
182         }
183       break;
184     }
185
186   default:
187     {
188       /* nothing to do but delete the dead expected-response structure */
189       /* this is normal. */
190       break;
191     }
192   }
193 }
194
195
196 /*******************************************************************
197   remove old name response entries
198
199   XXXX retry code needs to be added, including a retry wait period and a count
200        see name_query() and name_status() for suggested implementation.
201
202   ******************************************************************/
203 void expire_netbios_response_entries(time_t t)
204 {
205   struct subnet_record *d;
206
207   for (d = FIRST_SUBNET; d; d = NEXT_SUBNET_INCLUDING_WINS(d))
208   {
209     struct response_record *n, *nextn;
210
211     for (n = d->responselist; n; n = nextn)
212     {
213       nextn = n->next;
214
215       if (n->repeat_time <= t)
216       {
217         if (n->repeat_count > 0)
218         {
219           /* resend the entry */
220           initiate_netbios_packet(&n->response_id, n->fd, n->quest_type,
221                          n->name.name, n->name.name_type,
222                          n->nb_flags, n->bcast, n->recurse, n->send_ip);
223
224           n->repeat_time += n->repeat_interval; /* XXXX ms needed */
225           n->repeat_count--;
226
227         }
228         else
229         {
230           DEBUG(4,("timeout response %d for %s %s\n",
231                    n->response_id, namestr(&n->name),
232                    inet_ntoa(n->send_ip)));
233
234           dead_netbios_entry(d,n); /* process the non-response */
235           remove_response_record(d,n); /* remove the non-response */
236
237           continue;
238         }
239       }
240     }
241   }
242 }
243
244
245 /****************************************************************************
246   wrapper function to override a broadcast message and send it to the WINS
247   name server instead, if it exists. if wins is false, and there has been no
248   WINS server specified, the packet will NOT be sent.
249   ****************************************************************************/
250 struct response_record *queue_netbios_pkt_wins(
251                                 int fd,int quest_type,enum state_type state,
252                             char *name,int name_type,int nb_flags, time_t ttl,
253                                 int server_type, char *my_name, char *my_comment,
254                             BOOL bcast,BOOL recurse,
255                                 struct in_addr send_ip, struct in_addr reply_to_ip)
256 {
257   /* XXXX note: please see rfc1001.txt section 10 for details on this
258      function: it is currently inappropriate to use this - it will do
259      for now - once there is a clarification of B, M and P nodes and
260      which one samba is supposed to be
261    */
262
263   if ((!lp_wins_support()) && (*lp_wins_server()))
264     {
265       /* samba is not a WINS server, and we are using a WINS server */
266       struct in_addr wins_ip;
267       wins_ip = *interpret_addr2(lp_wins_server());
268
269       if (!zero_ip(wins_ip))
270         {
271           bcast = False;
272           send_ip = wins_ip;
273         }
274       else
275         {
276           /* oops. smb.conf's wins server parameter MUST be a host_name 
277              or an ip_address. */
278           DEBUG(0,("invalid smb.conf parameter 'wins server'\n"));
279         }
280     }
281
282   if (zero_ip(send_ip)) return NULL;
283
284   return queue_netbios_packet(wins_subnet,fd, quest_type, state, 
285                        name, name_type, nb_flags, ttl,
286                server_type,my_name,my_comment,
287                        bcast, recurse, send_ip, reply_to_ip);
288 }
289
290
291 /****************************************************************************
292   initiate a netbios name query to find someone's or someones' IP
293   this is intended to be used (not exclusively) for broadcasting to
294   master browsers (WORKGROUP(1d or 1b) or __MSBROWSE__(1)) to get
295   complete lists across a wide area network
296   ****************************************************************************/
297 struct response_record *queue_netbios_packet(struct subnet_record *d,
298                         int fd,int quest_type,enum state_type state,char *name,
299                         int name_type,int nb_flags, time_t ttl,
300                         int server_type, char *my_name, char *my_comment,
301                         BOOL bcast,BOOL recurse,
302                         struct in_addr send_ip, struct in_addr reply_to_ip)
303 {
304   struct response_record *n;
305   uint16 id = 0xffff;
306
307   /* ha ha. no. do NOT broadcast to 255.255.255.255: it's a pseudo address */
308   if (ip_equal(wins_ip, send_ip)) return NULL;
309
310   initiate_netbios_packet(&id, fd, quest_type, name, name_type,
311                           nb_flags, bcast, recurse, send_ip);
312
313   if (id == 0xffff) {
314     DEBUG(4,("did not initiate netbios packet: %s\n", inet_ntoa(send_ip)));
315     return NULL;
316   }
317   
318   if ((n = make_response_queue_record(state,id,fd,
319                                       quest_type,name,name_type,nb_flags,ttl,
320                                       server_type,my_name, my_comment,
321                                       bcast,recurse,send_ip,reply_to_ip)))
322     {
323       add_response_record(d,n);
324       return n;
325     }
326    return NULL;
327 }