LCOV - code coverage report
Current view: top level - libcli/nbt - namerefresh.c (source / functions) Hit Total Coverage
Test: coverage report for abartlet/fix-coverage dd10fb34 Lines: 111 165 67.3 %
Date: 2021-09-23 10:06:22 Functions: 7 7 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    send out a name refresh request
       5             : 
       6             :    Copyright (C) Andrew Tridgell 2005
       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             : #include "includes.h"
      23             : #include <tevent.h>
      24             : #include "../libcli/nbt/libnbt.h"
      25             : #include "../libcli/nbt/nbt_proto.h"
      26             : #include "lib/socket/socket.h"
      27             : #include "lib/util/tevent_ntstatus.h"
      28             : 
      29             : /*
      30             :   send a nbt name refresh request
      31             : */
      32          31 : struct nbt_name_request *nbt_name_refresh_send(struct nbt_name_socket *nbtsock,
      33             :                                                struct nbt_name_refresh *io)
      34             : {
      35             :         struct nbt_name_request *req;
      36             :         struct nbt_name_packet *packet;
      37             :         struct socket_address *dest;
      38             : 
      39          31 :         packet = talloc_zero(nbtsock, struct nbt_name_packet);
      40          31 :         if (packet == NULL) return NULL;
      41             : 
      42          31 :         packet->qdcount = 1;
      43          31 :         packet->arcount = 1;
      44          31 :         packet->operation = NBT_OPCODE_REFRESH;
      45          31 :         if (io->in.broadcast) {
      46           0 :                 packet->operation |= NBT_FLAG_BROADCAST;
      47             :         }
      48             : 
      49          31 :         packet->questions = talloc_array(packet, struct nbt_name_question, 1);
      50          31 :         if (packet->questions == NULL) goto failed;
      51             : 
      52          31 :         packet->questions[0].name           = io->in.name;
      53          31 :         packet->questions[0].question_type  = NBT_QTYPE_NETBIOS;
      54          31 :         packet->questions[0].question_class = NBT_QCLASS_IP;
      55             : 
      56          31 :         packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
      57          31 :         if (packet->additional == NULL) goto failed;
      58             : 
      59          31 :         packet->additional[0].name                   = io->in.name;
      60          31 :         packet->additional[0].rr_type                = NBT_QTYPE_NETBIOS;
      61          31 :         packet->additional[0].rr_class               = NBT_QCLASS_IP;
      62          31 :         packet->additional[0].ttl                    = io->in.ttl;
      63          31 :         packet->additional[0].rdata.netbios.length   = 6;
      64          31 :         packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional,
      65             :                                                                      struct nbt_rdata_address, 1);
      66          31 :         if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed;
      67          31 :         packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags;
      68          62 :         packet->additional[0].rdata.netbios.addresses[0].ipaddr =
      69          62 :                 talloc_strdup(packet->additional, io->in.address);
      70             : 
      71          62 :         dest = socket_address_from_strings(nbtsock,
      72          31 :                                            nbtsock->sock->backend_name,
      73          31 :                                            io->in.dest_addr, io->in.dest_port);
      74          31 :         if (dest == NULL) goto failed;
      75          31 :         req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
      76             :                                     io->in.timeout, io->in.retries, false);
      77          31 :         if (req == NULL) goto failed;
      78             : 
      79          31 :         talloc_free(packet);
      80          31 :         return req;
      81             : 
      82           0 : failed:
      83           0 :         talloc_free(packet);
      84           0 :         return NULL;
      85             : }
      86             : 
      87             : /*
      88             :   wait for a refresh reply
      89             : */
      90          31 : _PUBLIC_ NTSTATUS nbt_name_refresh_recv(struct nbt_name_request *req,
      91             :                                TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io)
      92             : {
      93             :         NTSTATUS status;
      94             :         struct nbt_name_packet *packet;
      95             : 
      96          31 :         status = nbt_name_request_recv(req);
      97          62 :         if (!NT_STATUS_IS_OK(status) ||
      98          31 :             req->num_replies == 0) {
      99           0 :                 talloc_free(req);
     100           0 :                 return status;
     101             :         }
     102             : 
     103          31 :         packet = req->replies[0].packet;
     104          31 :         io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
     105             : 
     106          62 :         if (packet->ancount != 1 ||
     107          62 :             packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
     108          31 :             packet->answers[0].rr_class != NBT_QCLASS_IP) {
     109           0 :                 talloc_free(req);
     110           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     111             :         }
     112             : 
     113          31 :         io->out.rcode = packet->operation & NBT_RCODE;
     114          31 :         io->out.name = packet->answers[0].name;
     115          31 :         if (packet->answers[0].rdata.netbios.length < 6) {
     116           0 :                 talloc_free(req);
     117           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     118             :         }
     119          31 :         io->out.reply_addr = talloc_steal(mem_ctx,
     120             :                                           packet->answers[0].rdata.netbios.addresses[0].ipaddr);
     121          31 :         talloc_steal(mem_ctx, io->out.name.name);
     122          31 :         talloc_steal(mem_ctx, io->out.name.scope);
     123             : 
     124          31 :         talloc_free(req);
     125             : 
     126          31 :         return NT_STATUS_OK;
     127             : }
     128             : 
     129             : /*
     130             :   synchronous name refresh request
     131             : */
     132           1 : _PUBLIC_ NTSTATUS nbt_name_refresh(struct nbt_name_socket *nbtsock,
     133             :                            TALLOC_CTX *mem_ctx, struct nbt_name_refresh *io)
     134             : {
     135           1 :         struct nbt_name_request *req = nbt_name_refresh_send(nbtsock, io);
     136           1 :         return nbt_name_refresh_recv(req, mem_ctx, io);
     137             : }
     138             : 
     139             : 
     140             : 
     141             : /**
     142             :   a wins name refresh with multiple WINS servers and multiple
     143             :   addresses to refresh. Try each WINS server in turn, until we get a
     144             :   reply for each address
     145             : */
     146             : struct nbt_name_refresh_wins_state {
     147             :         struct nbt_name_socket *nbtsock;
     148             :         struct nbt_name_refresh *io;
     149             :         char **wins_servers;
     150             :         uint16_t wins_port;
     151             :         char **addresses;
     152             :         int address_idx;
     153             : };
     154             : 
     155             : static void nbt_name_refresh_wins_handler(struct nbt_name_request *subreq);
     156             : 
     157             : /**
     158             :   the async send call for a multi-server WINS refresh
     159             : */
     160          30 : _PUBLIC_ struct tevent_req *nbt_name_refresh_wins_send(TALLOC_CTX *mem_ctx,
     161             :                                                 struct tevent_context *ev,
     162             :                                                 struct nbt_name_socket *nbtsock,
     163             :                                                 struct nbt_name_refresh_wins *io)
     164             : {
     165             :         struct tevent_req *req;
     166             :         struct nbt_name_refresh_wins_state *state;
     167             :         struct nbt_name_request *subreq;
     168             : 
     169          30 :         req = tevent_req_create(mem_ctx, &state,
     170             :                                 struct nbt_name_refresh_wins_state);
     171          30 :         if (req == NULL) {
     172           0 :                 return NULL;
     173             :         }
     174             : 
     175          30 :         state->io = talloc(state, struct nbt_name_refresh);
     176          30 :         if (tevent_req_nomem(state->io, req)) {
     177           0 :                 return tevent_req_post(req, ev);
     178             :         }
     179             : 
     180          30 :         if (io->in.wins_servers == NULL) {
     181           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     182           0 :                 return tevent_req_post(req, ev);
     183             :         }
     184             : 
     185          30 :         if (io->in.wins_servers[0] == NULL) {
     186           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     187           0 :                 return tevent_req_post(req, ev);
     188             :         }
     189             : 
     190          30 :         if (io->in.addresses == NULL) {
     191           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     192           0 :                 return tevent_req_post(req, ev);
     193             :         }
     194             : 
     195          30 :         if (io->in.addresses[0] == NULL) {
     196           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     197           0 :                 return tevent_req_post(req, ev);
     198             :         }
     199             : 
     200          30 :         state->wins_port = io->in.wins_port;
     201          30 :         state->wins_servers = str_list_copy(state, io->in.wins_servers);
     202          30 :         if (tevent_req_nomem(state->wins_servers, req)) {
     203           0 :                 return tevent_req_post(req, ev);
     204             :         }
     205             : 
     206          30 :         state->addresses = str_list_copy(state, io->in.addresses);
     207          30 :         if (tevent_req_nomem(state->addresses, req)) {
     208           0 :                 return tevent_req_post(req, ev);
     209             :         }
     210             : 
     211          30 :         state->io->in.name            = io->in.name;
     212          30 :         state->io->in.dest_addr       = state->wins_servers[0];
     213          30 :         state->io->in.dest_port       = state->wins_port;
     214          30 :         state->io->in.address         = io->in.addresses[0];
     215          30 :         state->io->in.nb_flags        = io->in.nb_flags;
     216          30 :         state->io->in.broadcast       = false;
     217          30 :         state->io->in.ttl             = io->in.ttl;
     218          30 :         state->io->in.timeout         = 2;
     219          30 :         state->io->in.retries         = 2;
     220             : 
     221          30 :         state->nbtsock     = nbtsock;
     222          30 :         state->address_idx = 0;
     223             : 
     224          30 :         subreq = nbt_name_refresh_send(nbtsock, state->io);
     225          30 :         if (tevent_req_nomem(subreq, req)) {
     226           0 :                 return tevent_req_post(req, ev);
     227             :         }
     228             : 
     229          30 :         subreq->async.fn = nbt_name_refresh_wins_handler;
     230          30 :         subreq->async.private_data = req;
     231             : 
     232          30 :         return req;
     233             : }
     234             : 
     235          30 : static void nbt_name_refresh_wins_handler(struct nbt_name_request *subreq)
     236             : {
     237          30 :         struct tevent_req *req =
     238          30 :                 talloc_get_type_abort(subreq->async.private_data,
     239             :                 struct tevent_req);
     240          30 :         struct nbt_name_refresh_wins_state *state =
     241          30 :                 tevent_req_data(req,
     242             :                 struct nbt_name_refresh_wins_state);
     243             :         NTSTATUS status;
     244             : 
     245          30 :         status = nbt_name_refresh_recv(subreq, state, state->io);
     246          30 :         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
     247             :                 /* the refresh timed out - try the next WINS server */
     248           0 :                 state->wins_servers++;
     249           0 :                 if (state->wins_servers[0] == NULL) {
     250           0 :                         tevent_req_nterror(req, status);
     251           0 :                         return;
     252             :                 }
     253             : 
     254           0 :                 state->address_idx = 0;
     255           0 :                 state->io->in.dest_addr = state->wins_servers[0];
     256           0 :                 state->io->in.dest_port = state->wins_port;
     257           0 :                 state->io->in.address   = state->addresses[0];
     258             : 
     259           0 :                 subreq = nbt_name_refresh_send(state->nbtsock, state->io);
     260           0 :                 if (tevent_req_nomem(subreq, req)) {
     261           0 :                         return;
     262             :                 }
     263           0 :                 subreq->async.fn = nbt_name_refresh_wins_handler;
     264           0 :                 subreq->async.private_data = req;
     265          30 :         } else if (!NT_STATUS_IS_OK(status)) {
     266           0 :                 tevent_req_nterror(req, status);
     267           0 :                 return;
     268             :         }
     269             : 
     270          60 :         if (state->io->out.rcode == 0 &&
     271          30 :             state->addresses[state->address_idx+1] != NULL) {
     272             :                 /* refresh our next address */
     273           0 :                 state->io->in.address = state->addresses[++(state->address_idx)];
     274           0 :                 subreq = nbt_name_refresh_send(state->nbtsock, state->io);
     275           0 :                 if (tevent_req_nomem(subreq, req)) {
     276           0 :                         return;
     277             :                 }
     278           0 :                 subreq->async.fn = nbt_name_refresh_wins_handler;
     279           0 :                 subreq->async.private_data = req;
     280           0 :                 return;
     281             :         }
     282             : 
     283          30 :         tevent_req_done(req);
     284             : }
     285             : 
     286             : /*
     287             :   multi-homed WINS name refresh - recv side
     288             : */
     289          30 : _PUBLIC_ NTSTATUS nbt_name_refresh_wins_recv(struct tevent_req *req,
     290             :                                              TALLOC_CTX *mem_ctx,
     291             :                                              struct nbt_name_refresh_wins *io)
     292             : {
     293          30 :         struct nbt_name_refresh_wins_state *state =
     294          30 :                 tevent_req_data(req,
     295             :                 struct nbt_name_refresh_wins_state);
     296             :         NTSTATUS status;
     297             : 
     298          30 :         if (tevent_req_is_nterror(req, &status)) {
     299           0 :                 tevent_req_received(req);
     300           0 :                 return status;
     301             :         }
     302             : 
     303          30 :         io->out.wins_server = talloc_move(mem_ctx, &state->wins_servers[0]);
     304          30 :         io->out.rcode = state->io->out.rcode;
     305             : 
     306          30 :         tevent_req_received(req);
     307          30 :         return NT_STATUS_OK;
     308             : }
     309             : 
     310             : /*
     311             :   multi-homed WINS refresh - sync interface
     312             : */
     313          30 : _PUBLIC_ NTSTATUS nbt_name_refresh_wins(struct nbt_name_socket *nbtsock,
     314             :                                         TALLOC_CTX *mem_ctx,
     315             :                                         struct nbt_name_refresh_wins *io)
     316             : {
     317          30 :         TALLOC_CTX *frame = talloc_stackframe();
     318             :         struct tevent_context *ev;
     319             :         struct tevent_req *subreq;
     320             :         NTSTATUS status;
     321             : 
     322             :         /*
     323             :          * TODO: create a temporary event context
     324             :          */
     325          30 :         ev = nbtsock->event_ctx;
     326             : 
     327          30 :         subreq = nbt_name_refresh_wins_send(frame, ev, nbtsock, io);
     328          30 :         if (subreq == NULL) {
     329           0 :                 talloc_free(frame);
     330           0 :                 return NT_STATUS_NO_MEMORY;
     331             :         }
     332             : 
     333          30 :         if (!tevent_req_poll(subreq, ev)) {
     334           0 :                 status = map_nt_error_from_unix_common(errno);
     335           0 :                 talloc_free(frame);
     336           0 :                 return status;
     337             :         }
     338             : 
     339          30 :         status = nbt_name_refresh_wins_recv(subreq, mem_ctx, io);
     340          30 :         if (!NT_STATUS_IS_OK(status)) {
     341           0 :                 talloc_free(frame);
     342           0 :                 return status;
     343             :         }
     344             : 
     345          30 :         TALLOC_FREE(frame);
     346          30 :         return NT_STATUS_OK;
     347             : }

Generated by: LCOV version 1.13