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