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