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