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