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