Half-way though the big conversion of all nmbd access to wire elements being
[samba.git] / source3 / 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       if (!nmb->answers)
85       {
86         dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
87         dbgtext( "IP %s ", inet_ntoa(p->ip) );
88         dbgtext( "returned a success response with no answer\n" );
89         return;
90       }
91
92       success = True;
93
94       putip((char *)&answer_ip,&nmb->answers->rdata[2]);
95       if( DEBUGLVL( 5 ) )
96         {
97         dbgtext( "query_name_response: On subnet %s ", subrec->subnet_name );
98         dbgtext( "- positive response from IP %s ", inet_ntoa(p->ip) );
99         dbgtext( "for name %s.  ", nmb_namestr(question_name) );
100         dbgtext( "IP of that name is %s\n", inet_ntoa(answer_ip) );
101         }
102
103       /* Interestingly, we could add these names to our namelists, and
104          change nmbd to a model that checked its own name cache first,
105          before sending out a query. This is a task for another day, though.
106        */
107     }
108   }
109   else if( rrec->num_msgs > 1)
110   {
111     if( DEBUGLVL( 0 ) )
112       {
113       if (nmb->answers)
114         putip( (char *)&answer_ip, &nmb->answers->rdata[2] );
115       dbgtext( "query_name_response: " );
116       dbgtext( "Multiple (%d) responses ", rrec->num_msgs );
117       dbgtext( "received for a query on subnet %s ", subrec->subnet_name );
118       dbgtext( "for name %s.\nThis response ", nmb_namestr(question_name) );
119       dbgtext( "was from IP %s, reporting ", inet_ntoa(p->ip) );
120       dbgtext( "an IP address of %s.\n", inet_ntoa(answer_ip) );
121       }
122
123     /* We have already called the success or fail function, so we
124        don't call again here. Leave the response record around in
125        case we get more responses. */
126
127     return; 
128   }
129   
130   if(success && rrec->success_fn)
131     (*(query_name_success_function)rrec->success_fn)(subrec, rrec->userdata, question_name, answer_ip, nmb->answers);
132   else if( rrec->fail_fn)
133     (*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, nmb->header.rcode);
134
135 }
136
137 /****************************************************************************
138  Deal with a timeout when querying a name.
139 ****************************************************************************/
140
141 static void query_name_timeout_response(struct subnet_record *subrec,
142                        struct response_record *rrec)
143 {
144   struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
145   /* We can only fail here, never succeed. */
146   BOOL failed = True;
147   struct nmb_name *question_name = &sent_nmb->question.question_name;
148
149   if(rrec->num_msgs != 0)
150   {
151     /* We got at least one response, and have called the success/fail
152        function already. */
153
154     failed = False; 
155   }
156
157   if(failed)
158   {
159     if( DEBUGLVL( 5 ) )
160       {
161       dbgtext( "query_name_timeout_response: No response to " );
162       dbgtext( "query for name %s ", nmb_namestr(question_name) );
163       dbgtext( "on subnet %s.\n", subrec->subnet_name );
164       }
165     if(rrec->fail_fn)
166       (*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, 0);
167   }
168
169   remove_response_record(subrec, rrec);
170 }
171
172 /****************************************************************************
173  Lookup a name on our local namelists. We check the lmhosts file first. If the
174  name is not there we look for the name on the given subnet.
175 ****************************************************************************/
176
177 static BOOL query_local_namelists(struct subnet_record *subrec, struct nmb_name *nmbname,
178                                   struct name_record **namerecp) 
179 {
180   struct name_record *namerec;
181
182   *namerecp = NULL;
183
184   if(find_name_in_lmhosts(nmbname, namerecp))
185     return True;
186   
187   if((namerec = find_name_on_subnet(subrec, nmbname, FIND_ANY_NAME))==NULL)
188     return False;
189
190   if( NAME_IS_ACTIVE(namerec)
191    && ( (namerec->data.source == SELF_NAME)
192      || (namerec->data.source == LMHOSTS_NAME) ) )
193   {
194     *namerecp = namerec;
195     return True;
196   } 
197   return False;
198 }
199
200 /****************************************************************************
201  Try and query for a name.
202 ****************************************************************************/
203
204 BOOL query_name(struct subnet_record *subrec, const char *name, int type,
205                    query_name_success_function success_fn,
206                    query_name_fail_function fail_fn, 
207                    struct userdata_struct *userdata)
208 {
209   struct nmb_name nmbname;
210   struct name_record *namerec;
211
212   make_nmb_name(&nmbname, name, type);
213
214   /*
215    * We need to check our local namelists first.
216    * It may be an magic name, lmhosts name or just
217    * a name we have registered.
218    */
219
220   if(query_local_namelists(subrec, &nmbname, &namerec) == True)
221   {
222     struct res_rec rrec;
223     int i;
224
225     memset((char *)&rrec, '\0', sizeof(struct res_rec));
226
227     /* Fake up the needed res_rec just in case it's used. */
228     rrec.rr_name = nmbname;
229     rrec.rr_type = RR_TYPE_NB;
230     rrec.rr_class = RR_CLASS_IN;
231     rrec.ttl = PERMANENT_TTL;
232     rrec.rdlength = namerec->data.num_ips * 6;
233     if(rrec.rdlength > MAX_DGRAM_SIZE)
234     {
235       if( DEBUGLVL( 0 ) )
236         {
237         dbgtext( "query_name: nmbd internal error - " );
238         dbgtext( "there are %d ip addresses ", namerec->data.num_ips );
239         dbgtext( "for name %s.\n", nmb_namestr(&nmbname) );
240         }
241       return False;
242     }
243
244     for( i = 0; i < namerec->data.num_ips; i++)
245     {
246       set_nb_flags( &rrec.rdata[i*6], namerec->data.nb_flags );
247       putip( &rrec.rdata[(i*6) + 2], (char *)&namerec->data.ip[i]);
248     }
249
250     /* Call the success function directly. */
251     if(success_fn)
252       (*(query_name_success_function)success_fn)(subrec, userdata, &nmbname, namerec->data.ip[0], &rrec);
253     return False;
254   }
255
256   if(queue_query_name( subrec,
257         query_name_response,
258         query_name_timeout_response,
259         success_fn,
260         fail_fn,
261         userdata,
262         &nmbname) == NULL)
263   {
264     if( DEBUGLVL( 0 ) )
265       {
266       dbgtext( "query_name: Failed to send packet " );
267       dbgtext( "trying to query name %s\n", nmb_namestr(&nmbname) );
268       }
269     return True;
270   }
271   return False;
272 }
273
274 /****************************************************************************
275  Try and query for a name from nmbd acting as a WINS server.
276 ****************************************************************************/
277
278 BOOL query_name_from_wins_server(struct in_addr ip_to, 
279                    const char *name, int type,
280                    query_name_success_function success_fn,
281                    query_name_fail_function fail_fn, 
282                    struct userdata_struct *userdata)
283 {
284   struct nmb_name nmbname;
285
286   make_nmb_name(&nmbname, name, type);
287
288   if(queue_query_name_from_wins_server( ip_to,
289         query_name_response,
290         query_name_timeout_response,
291         success_fn,
292         fail_fn,
293         userdata,
294         &nmbname) == NULL)
295   {
296     if( DEBUGLVL( 0 ) )
297       {
298       dbgtext( "query_name_from_wins_server: Failed to send packet " );
299       dbgtext( "trying to query name %s\n", nmb_namestr(&nmbname) );
300       }
301     return True;
302   }
303   return False;
304 }