spoolss: use nstring_array in spoolss_EnumPrinterKey.
[Samba.git] / source3 / nmbd / nmbd_namequery.c
blobc1c5f5238a6effc7c989d25eb00df9b58f0e07e4
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
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.
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.
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/>.
23 #include "includes.h"
25 /****************************************************************************
26 Deal with a response packet when querying a name.
27 ****************************************************************************/
29 static void query_name_response( struct subnet_record *subrec,
30 struct response_record *rrec,
31 struct packet_struct *p)
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;
38 zero_ip_v4(&answer_ip);
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;
45 if(rrec->num_msgs == 1) {
46 /* This is the first response. */
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. */
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 );
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;
70 rrec->num_msgs--;
71 return;
72 } else if(nmb->header.rcode != 0) {
74 success = False;
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 );
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;
90 success = True;
92 putip((char *)&answer_ip,&nmb->answers->rdata[2]);
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) );
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.
106 } else if( rrec->num_msgs > 1) {
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) );
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. */
123 return;
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);
133 /****************************************************************************
134 Deal with a timeout when querying a name.
135 ****************************************************************************/
137 static void query_name_timeout_response(struct subnet_record *subrec,
138 struct response_record *rrec)
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;
145 if(rrec->num_msgs != 0) {
146 /* We got at least one response, and have called the success/fail
147 function already. */
149 failed = False;
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 );
159 if(rrec->fail_fn)
160 (*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, 0);
163 remove_response_record(subrec, rrec);
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 ****************************************************************************/
171 static bool query_local_namelists(struct subnet_record *subrec, struct nmb_name *nmbname,
172 struct name_record **namerecp)
174 struct name_record *namerec;
176 *namerecp = NULL;
178 if(find_name_in_lmhosts(nmbname, namerecp))
179 return True;
181 if((namerec = find_name_on_subnet(subrec, nmbname, FIND_ANY_NAME))==NULL)
182 return False;
184 if( NAME_IS_ACTIVE(namerec) && ( (namerec->data.source == SELF_NAME) || (namerec->data.source == LMHOSTS_NAME) ) ) {
185 *namerecp = namerec;
186 return True;
188 return False;
191 /****************************************************************************
192 Try and query for a name.
193 ****************************************************************************/
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)
200 struct nmb_name nmbname;
201 struct name_record *namerec;
203 make_nmb_name(&nmbname, name, type);
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.
211 if(query_local_namelists(subrec, &nmbname, &namerec) == True) {
212 struct res_rec rrec;
213 int i;
215 memset((char *)&rrec, '\0', sizeof(struct res_rec));
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) );
229 return False;
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]);
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;
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) );
248 return True;
250 return False;
253 /****************************************************************************
254 Try and query for a name from nmbd acting as a WINS server.
255 ****************************************************************************/
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)
263 struct nmb_name nmbname;
265 make_nmb_name(&nmbname, name, type);
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) );
272 return True;
274 return False;