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