first pass at updating head branch to be to be the same as the SAMBA_2_0 branch
[kai/samba.git] / source3 / nmbd / nmbd_namequery.c
1 /* 
2    Unix SMB/Netbios implementation.
3    Version 1.9.
4    NBT netbios routines and daemon - version 2
5    Copyright (C) Andrew Tridgell 1994-1998
6    Copyright (C) Luke Kenneth Casson Leighton 1994-1998
7    Copyright (C) Jeremy Allison 1994-1998
8    
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 2 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22    
23 */
24
25 #include "includes.h"
26
27 extern int DEBUGLEVEL;
28
29 extern pstring scope;
30
31 /****************************************************************************
32  Deal with a response packet when querying a name.
33 ****************************************************************************/
34
35 static void query_name_response(struct subnet_record *subrec,
36                        struct response_record *rrec, struct packet_struct *p)
37 {
38   struct nmb_packet *nmb = &p->packet.nmb;
39   BOOL success = False;
40   struct nmb_name *question_name = 
41                            &rrec->packet->packet.nmb.question.question_name;
42   struct in_addr answer_ip;
43
44   /* Ensure we don't retry the query but leave the response record cleanup
45      to the timeout code. We may get more answer responses in which case
46      we should mark the name in conflict.. */
47   rrec->repeat_count = 0;
48
49   if(rrec->num_msgs == 1)
50   {
51     /* This is the first response. */
52
53     if(nmb->header.opcode == NMB_WACK_OPCODE)
54     {
55       /* WINS server is telling us to wait. Pretend we didn't get
56          the response but don't send out any more query requests. */
57   
58       DEBUG(5,("query_name_response: WACK from WINS server %s in querying \
59 name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(question_name), subrec->subnet_name));
60   
61       rrec->repeat_count = 0;
62       /* How long we should wait for. */
63       rrec->repeat_time = p->timestamp + nmb->answers->ttl;
64       rrec->num_msgs--;
65       return;
66     }
67     else if(nmb->header.rcode != 0)
68     {
69       success = False;
70
71       DEBUG(5,("query_name_response: On subnet %s - negative response \
72 from IP %s for name %s. Error code was %d.\n", subrec->subnet_name, inet_ntoa(p->ip), 
73                       nmb_namestr(question_name), nmb->header.rcode));
74     }
75     else
76     {
77       success = True;
78
79       putip((char *)&answer_ip,&nmb->answers->rdata[2]);
80       DEBUG(5,("query_name_response: On subnet %s - positive response from IP %s \
81 for name %s. IP of that name is %s\n", subrec->subnet_name, inet_ntoa(p->ip),
82                     nmb_namestr(question_name), inet_ntoa(answer_ip)));
83
84       /* Interestingly, we could add these names to our namelists, and
85          change nmbd to a model that checked its own name cache first,
86          before sending out a query. This is a task for another day, though.
87        */
88     }
89   }
90   else if( rrec->num_msgs > 1)
91   {
92     DEBUG(0,("query_name_response: Multiple (%d) responses received for a query on \
93 subnet %s for name %s. This response was from IP %s\n", 
94         rrec->num_msgs, subrec->subnet_name, nmb_namestr(question_name), 
95         inet_ntoa(p->ip) ));
96
97     /* We have already called the success or fail function, so we
98        don't call again here. Leave the response record around in
99        case we get more responses. */
100
101     return; 
102   }
103   
104   if(success && rrec->success_fn)
105     (*rrec->success_fn)(subrec, rrec->userdata, question_name, answer_ip, nmb->answers);
106   else if( rrec->fail_fn)
107     (*rrec->fail_fn)(subrec, rrec, question_name, nmb->header.rcode);
108
109 }
110
111 /****************************************************************************
112  Deal with a timeout when querying a name.
113 ****************************************************************************/
114
115 static void query_name_timeout_response(struct subnet_record *subrec,
116                        struct response_record *rrec)
117 {
118   struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
119   /* We can only fail here, never succeed. */
120   BOOL failed = True;
121   struct nmb_name *question_name = &sent_nmb->question.question_name;
122
123   if(rrec->num_msgs != 0)
124   {
125     /* We got at least one response, and have called the success/fail
126        function already. */
127
128     failed = False; 
129   }
130
131   if(failed)
132   {
133     DEBUG(5,("query_name_timeout_response: No response to querying name %s on subnet %s.\n",
134         nmb_namestr(question_name), subrec->subnet_name));
135
136     if(rrec->fail_fn)
137       (*rrec->fail_fn)(subrec, rrec, question_name, 0);
138   }
139
140   remove_response_record(subrec, rrec);
141 }
142
143 /****************************************************************************
144  Lookup a name on our local namelists. We check the lmhosts file first. If the
145  name is not there we look for the name on the given subnet.
146 ****************************************************************************/
147
148 static BOOL query_local_namelists(struct subnet_record *subrec, struct nmb_name *nmbname,
149                                   struct name_record **namerecp) 
150 {
151   struct name_record *namerec;
152
153   *namerecp = NULL;
154
155   if(find_name_in_lmhosts(nmbname, namerecp))
156     return True;
157   
158   if((namerec = find_name_on_subnet(subrec, nmbname, FIND_ANY_NAME))==NULL)
159     return False;
160
161   if( NAME_IS_ACTIVE(namerec)
162    && ( (namerec->data.source == SELF_NAME)
163      || (namerec->data.source == LMHOSTS_NAME) ) )
164   {
165     *namerecp = namerec;
166     return True;
167   } 
168   return False;
169 }
170
171 /****************************************************************************
172  Try and query for a name.
173 ****************************************************************************/
174
175 BOOL query_name(struct subnet_record *subrec, char *name, int type,
176                    query_name_success_function success_fn,
177                    query_name_fail_function fail_fn, 
178                    struct userdata_struct *userdata)
179 {
180   struct nmb_name nmbname;
181   struct name_record *namerec;
182
183   make_nmb_name(&nmbname, name, type, scope);
184
185   /*
186    * We need to check our local namelists first.
187    * It may be an magic name, lmhosts name or just
188    * a name we have registered.
189    */
190
191   if(query_local_namelists(subrec, &nmbname, &namerec) == True)
192   {
193     struct res_rec rrec;
194     int i;
195
196     memset((char *)&rrec, '\0', sizeof(struct res_rec));
197
198     /* Fake up the needed res_rec just in case it's used. */
199     rrec.rr_name = nmbname;
200     rrec.rr_type = RR_TYPE_NB;
201     rrec.rr_class = RR_CLASS_IN;
202     rrec.ttl = PERMANENT_TTL;
203     rrec.rdlength = namerec->data.num_ips * 6;
204     if(rrec.rdlength > MAX_DGRAM_SIZE)
205     {
206       DEBUG(0,("query_name: nmbd internal error - there are %d ip addresses for name %s.\n",
207                namerec->data.num_ips, nmb_namestr(&nmbname) ));
208       return False;
209     }
210
211     for( i = 0; i < namerec->data.num_ips; i++)
212     {
213       set_nb_flags( &rrec.rdata[i*6], namerec->data.nb_flags );
214       putip( &rrec.rdata[(i*6) + 2], (char *)&namerec->data.ip[i]);
215     }
216
217     /* Call the success function directly. */
218     if(success_fn)
219       (*success_fn)(subrec, userdata, &nmbname, namerec->data.ip[0], &rrec);
220     return False;
221   }
222
223   if(queue_query_name( subrec,
224         query_name_response,
225         query_name_timeout_response,
226         success_fn,
227         fail_fn,
228         userdata,
229         &nmbname) == NULL)
230   {
231     DEBUG(0,("query_name: Failed to send packet trying to query name %s\n",
232           nmb_namestr(&nmbname)));
233     return True;
234   }
235   return False;
236 }
237
238 /****************************************************************************
239  Try and query for a name from nmbd acting as a WINS server.
240 ****************************************************************************/
241
242 BOOL query_name_from_wins_server(struct in_addr ip_to, 
243                    char *name, int type,
244                    query_name_success_function success_fn,
245                    query_name_fail_function fail_fn, 
246                    struct userdata_struct *userdata)
247 {
248   struct nmb_name nmbname;
249
250   make_nmb_name(&nmbname, name, type, scope);
251
252   if(queue_query_name_from_wins_server( ip_to,
253         query_name_response,
254         query_name_timeout_response,
255         success_fn,
256         fail_fn,
257         userdata,
258         &nmbname) == NULL)
259   {
260     DEBUG(0,("query_name_from_wins_server: Failed to send packet trying to query name %s\n",
261           nmb_namestr(&nmbname)));
262     return True;
263   }
264   return False;
265 }