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