root/source3/nmbd/nmbd_namequery.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. query_name_response
  2. query_name_timeout_response
  3. query_local_namelists
  4. query_name
  5. query_name_from_wins_server

   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,
     /* [<][>][^][v][top][bottom][index][help] */
  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 
 137 static void query_name_timeout_response(struct subnet_record *subrec,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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,
     /* [<][>][^][v][top][bottom][index][help] */
 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, 
     /* [<][>][^][v][top][bottom][index][help] */
 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 }

/* [<][>][^][v][top][bottom][index][help] */