sync with SAMBA_2_2
[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 /****************************************************************************
30  Deal with a response packet when querying a name.
31 ****************************************************************************/
32
33 static void query_name_response(struct subnet_record *subrec,
34                        struct response_record *rrec, struct packet_struct *p)
35 {
36   struct nmb_packet *nmb = &p->packet.nmb;
37   BOOL success = False;
38   struct nmb_name *question_name = 
39                            &rrec->packet->packet.nmb.question.question_name;
40   struct in_addr answer_ip;
41
42   /* Ensure we don't retry the query but leave the response record cleanup
43      to the timeout code. We may get more answer responses in which case
44      we should mark the name in conflict.. */
45   rrec->repeat_count = 0;
46
47   if(rrec->num_msgs == 1)
48   {
49     /* This is the first response. */
50
51     if(nmb->header.opcode == NMB_WACK_OPCODE)
52     {
53       /* WINS server is telling us to wait. Pretend we didn't get
54          the response but don't send out any more query requests. */
55   
56       DEBUG(5,("query_name_response: WACK from WINS server %s in querying \
57 name %s on subnet %s.\n", inet_ntoa(p->ip), nmb_namestr(question_name), subrec->subnet_name));
58   
59       rrec->repeat_count = 0;
60       /* How long we should wait for. */
61       rrec->repeat_time = p->timestamp + nmb->answers->ttl;
62       rrec->num_msgs--;
63       return;
64     }
65     else if(nmb->header.rcode != 0)
66     {
67       success = False;
68
69       DEBUG(5,("query_name_response: On subnet %s - negative response \
70 from IP %s for name %s. Error code was %d.\n", subrec->subnet_name, inet_ntoa(p->ip), 
71                       nmb_namestr(question_name), nmb->header.rcode));
72     }
73     else
74     {
75       success = True;
76
77       putip((char *)&answer_ip,&nmb->answers->rdata[2]);
78       DEBUG(5,("query_name_response: On subnet %s - positive response from IP %s \
79 for name %s. IP of that name is %s\n", subrec->subnet_name, inet_ntoa(p->ip),
80                     nmb_namestr(question_name), inet_ntoa(answer_ip)));
81
82       /* Interestingly, we could add these names to our namelists, and
83          change nmbd to a model that checked its own name cache first,
84          before sending out a query. This is a task for another day, though.
85        */
86     }
87   }
88   else if( rrec->num_msgs > 1)
89   {
90     DEBUG(0,("query_name_response: Multiple (%d) responses received for a query on \
91 subnet %s for name %s. This response was from IP %s\n", 
92         rrec->num_msgs, subrec->subnet_name, nmb_namestr(question_name), 
93         inet_ntoa(p->ip) ));
94
95     /* We have already called the success or fail function, so we
96        don't call again here. Leave the response record around in
97        case we get more responses. */
98
99     return; 
100   }
101   
102   if(success && rrec->success_fn)
103     (*rrec->success_fn)(subrec, rrec->userdata, question_name, answer_ip, nmb->answers);
104   else if( rrec->fail_fn)
105     (*rrec->fail_fn)(subrec, rrec, question_name, nmb->header.rcode);
106
107 }
108
109 /****************************************************************************
110  Deal with a timeout when querying a name.
111 ****************************************************************************/
112
113 static void query_name_timeout_response(struct subnet_record *subrec,
114                        struct response_record *rrec)
115 {
116   struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
117   /* We can only fail here, never succeed. */
118   BOOL failed = True;
119   struct nmb_name *question_name = &sent_nmb->question.question_name;
120
121   if(rrec->num_msgs != 0)
122   {
123     /* We got at least one response, and have called the success/fail
124        function already. */
125
126     failed = False; 
127   }
128
129   if(failed)
130   {
131     DEBUG(5,("query_name_timeout_response: No response to querying name %s on subnet %s.\n",
132         nmb_namestr(question_name), subrec->subnet_name));
133
134     if(rrec->fail_fn)
135       (*rrec->fail_fn)(subrec, rrec, question_name, 0);
136   }
137
138   remove_response_record(subrec, rrec);
139 }
140
141 /****************************************************************************
142  Lookup a name on our local namelists. We check the lmhosts file first. If the
143  name is not there we look for the name on the given subnet.
144 ****************************************************************************/
145
146 static BOOL query_local_namelists(struct subnet_record *subrec, struct nmb_name *nmbname,
147                                   struct name_record **namerecp) 
148 {
149   struct name_record *namerec;
150
151   *namerecp = NULL;
152
153   if(find_name_in_lmhosts(nmbname, namerecp))
154     return True;
155   
156   if((namerec = find_name_on_subnet(subrec, nmbname, FIND_ANY_NAME))==NULL)
157     return False;
158
159   if( NAME_IS_ACTIVE(namerec)
160    && ( (namerec->data.source == SELF_NAME)
161      || (namerec->data.source == LMHOSTS_NAME) ) )
162   {
163     *namerecp = namerec;
164     return True;
165   } 
166   return False;
167 }
168
169 /****************************************************************************
170  Try and query for a name.
171 ****************************************************************************/
172
173 BOOL query_name(struct subnet_record *subrec, char *name, int type,
174                    query_name_success_function success_fn,
175                    query_name_fail_function fail_fn, 
176                    struct userdata_struct *userdata)
177 {
178   struct nmb_name nmbname;
179   struct name_record *namerec;
180
181   make_nmb_name(&nmbname, name, type);
182
183   /*
184    * We need to check our local namelists first.
185    * It may be an magic name, lmhosts name or just
186    * a name we have registered.
187    */
188
189   if(query_local_namelists(subrec, &nmbname, &namerec) == True)
190   {
191     struct res_rec rrec;
192     int i;
193
194     memset((char *)&rrec, '\0', sizeof(struct res_rec));
195
196     /* Fake up the needed res_rec just in case it's used. */
197     rrec.rr_name = nmbname;
198     rrec.rr_type = RR_TYPE_NB;
199     rrec.rr_class = RR_CLASS_IN;
200     rrec.ttl = PERMANENT_TTL;
201     rrec.rdlength = namerec->data.num_ips * 6;
202     if(rrec.rdlength > MAX_DGRAM_SIZE)
203     {
204       DEBUG(0,("query_name: nmbd internal error - there are %d ip addresses for name %s.\n",
205                namerec->data.num_ips, nmb_namestr(&nmbname) ));
206       return False;
207     }
208
209     for( i = 0; i < namerec->data.num_ips; i++)
210     {
211       set_nb_flags( &rrec.rdata[i*6], namerec->data.nb_flags );
212       putip( &rrec.rdata[(i*6) + 2], (char *)&namerec->data.ip[i]);
213     }
214
215     /* Call the success function directly. */
216     if(success_fn)
217       (*success_fn)(subrec, userdata, &nmbname, namerec->data.ip[0], &rrec);
218     return False;
219   }
220
221   if(queue_query_name( subrec,
222         query_name_response,
223         query_name_timeout_response,
224         success_fn,
225         fail_fn,
226         userdata,
227         &nmbname) == NULL)
228   {
229     DEBUG(0,("query_name: Failed to send packet trying to query name %s\n",
230           nmb_namestr(&nmbname)));
231     return True;
232   }
233   return False;
234 }
235
236 /****************************************************************************
237  Try and query for a name from nmbd acting as a WINS server.
238 ****************************************************************************/
239
240 BOOL query_name_from_wins_server(struct in_addr ip_to, 
241                    char *name, int type,
242                    query_name_success_function success_fn,
243                    query_name_fail_function fail_fn, 
244                    struct userdata_struct *userdata)
245 {
246   struct nmb_name nmbname;
247
248   make_nmb_name(&nmbname, name, type);
249
250   if(queue_query_name_from_wins_server( ip_to,
251         query_name_response,
252         query_name_timeout_response,
253         success_fn,
254         fail_fn,
255         userdata,
256         &nmbname) == NULL)
257   {
258     DEBUG(0,("query_name_from_wins_server: Failed to send packet trying to query name %s\n",
259           nmb_namestr(&nmbname)));
260     return True;
261   }
262   return False;
263 }