• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/router/samba-3.5.8/source3/nmbd/
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
29static 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_v4(&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
137static 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
171static 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
195bool 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
257bool 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}
276