LCOV - code coverage report
Current view: top level - source3/nmbd - nmbd_namequery.c (source / functions) Hit Total Coverage
Test: coverage report for master 70ed9daf Lines: 37 114 32.5 %
Date: 2024-01-11 09:59:51 Functions: 4 5 80.0 %

          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          56 : static void query_name_response( struct subnet_record   *subrec,
      31             :                                  struct response_record *rrec,
      32             :                                  struct packet_struct   *p)
      33             : {
      34          56 :         struct nmb_packet *nmb = &p->packet.nmb;
      35          56 :         bool success = False;
      36          56 :         struct nmb_name *question_name = &rrec->packet->packet.nmb.question.question_name;
      37             :         struct in_addr answer_ip;
      38             : 
      39          56 :         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          56 :         rrec->repeat_count = 0;
      45             : 
      46          56 :         if(rrec->num_msgs == 1) {
      47             :                 /* This is the first response. */
      48             : 
      49          56 :                 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          56 :                 } 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          56 :                         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          56 :                         success = True;
      92             : 
      93          56 :                         putip((char *)&answer_ip,&nmb->answers->rdata[2]);
      94             :         
      95          56 :                         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          56 :         if(success && rrec->success_fn)
     128          56 :                 (*(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          96 : static void query_name_timeout_response(struct subnet_record *subrec,
     139             :                        struct response_record *rrec)
     140             : {
     141          96 :         struct nmb_packet *sent_nmb = &rrec->packet->packet.nmb;
     142             :         /* We can only fail here, never succeed. */
     143          96 :         bool failed = True;
     144          96 :         struct nmb_name *question_name = &sent_nmb->question.question_name;
     145             : 
     146          96 :         if(rrec->num_msgs != 0) {
     147             :                 /* We got at least one response, and have called the success/fail
     148             :                         function already. */
     149             : 
     150          56 :                 failed = False; 
     151             :         }
     152             : 
     153          96 :         if(failed) {
     154          40 :                 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          40 :                 if(rrec->fail_fn)
     161          40 :                         (*(query_name_fail_function)rrec->fail_fn)(subrec, rrec, question_name, 0);
     162             :         }
     163             : 
     164          96 :         remove_response_record(subrec, rrec);
     165          96 : }
     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          96 : 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          96 :         *namerecp = NULL;
     178             : 
     179          96 :         if(find_name_in_lmhosts(nmbname, namerecp))
     180           0 :                 return True;
     181             :   
     182          96 :         if((namerec = find_name_on_subnet(subrec, nmbname, FIND_ANY_NAME))==NULL)
     183          96 :                 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          96 : 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          96 :         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          96 :         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          96 :         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          96 :         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             : }

Generated by: LCOV version 1.14