LCOV - code coverage report
Current view: top level - libcli/nbt - nameregister.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 183 258 70.9 %
Date: 2024-04-21 15:09:00 Functions: 10 11 90.9 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    send out a name registration 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 "librpc/gen_ndr/ndr_nbt.h"
      28             : #include "../lib/util/tevent_ntstatus.h"
      29             : 
      30             : /*
      31             :   send a nbt name registration request
      32             : */
      33        1368 : struct nbt_name_request *nbt_name_register_send(struct nbt_name_socket *nbtsock,
      34             :                                                 struct nbt_name_register *io)
      35             : {
      36          35 :         struct nbt_name_request *req;
      37          35 :         struct nbt_name_packet *packet;
      38          35 :         struct socket_address *dest;
      39             : 
      40        1368 :         packet = talloc_zero(nbtsock, struct nbt_name_packet);
      41        1368 :         if (packet == NULL) return NULL;
      42             : 
      43        1368 :         packet->qdcount = 1;
      44        1368 :         packet->arcount = 1;
      45        1368 :         if (io->in.multi_homed) {
      46         348 :                 packet->operation = NBT_OPCODE_MULTI_HOME_REG;
      47             :         } else {
      48        1020 :                 packet->operation = NBT_OPCODE_REGISTER;
      49             :         }
      50        1368 :         if (io->in.broadcast) {
      51         776 :                 packet->operation |= NBT_FLAG_BROADCAST;
      52             :         }
      53        1368 :         if (io->in.register_demand) {
      54         386 :                 packet->operation |= NBT_FLAG_RECURSION_DESIRED;
      55             :         }
      56             : 
      57        1368 :         packet->questions = talloc_array(packet, struct nbt_name_question, 1);
      58        1368 :         if (packet->questions == NULL) goto failed;
      59             : 
      60        1368 :         packet->questions[0].name           = io->in.name;
      61        1368 :         packet->questions[0].question_type  = NBT_QTYPE_NETBIOS;
      62        1368 :         packet->questions[0].question_class = NBT_QCLASS_IP;
      63             : 
      64        1368 :         packet->additional = talloc_array(packet, struct nbt_res_rec, 1);
      65        1368 :         if (packet->additional == NULL) goto failed;
      66             : 
      67        1368 :         packet->additional[0].name                   = io->in.name;
      68        1368 :         packet->additional[0].rr_type                = NBT_QTYPE_NETBIOS;
      69        1368 :         packet->additional[0].rr_class               = NBT_QCLASS_IP;
      70        1368 :         packet->additional[0].ttl                    = io->in.ttl;
      71        1368 :         packet->additional[0].rdata.netbios.length   = 6;
      72        1368 :         packet->additional[0].rdata.netbios.addresses = talloc_array(packet->additional,
      73             :                                                                      struct nbt_rdata_address, 1);
      74        1368 :         if (packet->additional[0].rdata.netbios.addresses == NULL) goto failed;
      75        1368 :         packet->additional[0].rdata.netbios.addresses[0].nb_flags = io->in.nb_flags;
      76        2736 :         packet->additional[0].rdata.netbios.addresses[0].ipaddr =
      77        1368 :                 talloc_strdup(packet->additional, io->in.address);
      78        1368 :         if (packet->additional[0].rdata.netbios.addresses[0].ipaddr == NULL) goto failed;
      79             : 
      80        1403 :         dest = socket_address_from_strings(packet, nbtsock->sock->backend_name,
      81        1368 :                                            io->in.dest_addr, io->in.dest_port);
      82        1368 :         if (dest == NULL) goto failed;
      83        1368 :         req = nbt_name_request_send(nbtsock, nbtsock, dest, packet,
      84             :                                     io->in.timeout, io->in.retries, false);
      85        1368 :         if (req == NULL) goto failed;
      86             : 
      87        1368 :         talloc_free(packet);
      88        1368 :         return req;
      89             : 
      90           0 : failed:
      91           0 :         talloc_free(packet);
      92           0 :         return NULL;
      93             : }
      94             : 
      95             : /*
      96             :   wait for a registration reply
      97             : */
      98        1368 : _PUBLIC_ NTSTATUS nbt_name_register_recv(struct nbt_name_request *req,
      99             :                                 TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
     100             : {
     101          35 :         NTSTATUS status;
     102          35 :         struct nbt_name_packet *packet;
     103             : 
     104        1368 :         status = nbt_name_request_recv(req);
     105        1368 :         if (!NT_STATUS_IS_OK(status) ||
     106         213 :             req->num_replies == 0) {
     107        1155 :                 talloc_free(req);
     108        1155 :                 return status;
     109             :         }
     110             : 
     111         213 :         packet = req->replies[0].packet;
     112         213 :         io->out.reply_from = talloc_steal(mem_ctx, req->replies[0].dest->addr);
     113             : 
     114         213 :         if (packet->ancount != 1 ||
     115         213 :             packet->answers[0].rr_type != NBT_QTYPE_NETBIOS ||
     116         212 :             packet->answers[0].rr_class != NBT_QCLASS_IP) {
     117           0 :                 talloc_free(req);
     118           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     119             :         }
     120             : 
     121         213 :         io->out.rcode = packet->operation & NBT_RCODE;
     122         213 :         io->out.name = packet->answers[0].name;
     123         213 :         if (packet->answers[0].rdata.netbios.length < 6) {
     124           0 :                 talloc_free(req);
     125           0 :                 return NT_STATUS_INVALID_NETWORK_RESPONSE;
     126             :         }
     127         213 :         io->out.reply_addr = talloc_steal(mem_ctx,
     128             :                                           packet->answers[0].rdata.netbios.addresses[0].ipaddr);
     129         213 :         talloc_steal(mem_ctx, io->out.name.name);
     130         213 :         talloc_steal(mem_ctx, io->out.name.scope);
     131             : 
     132         213 :         talloc_free(req);
     133             : 
     134         213 :         return NT_STATUS_OK;
     135             : }
     136             : 
     137             : /*
     138             :   synchronous name registration request
     139             : */
     140          68 : _PUBLIC_ NTSTATUS nbt_name_register(struct nbt_name_socket *nbtsock,
     141             :                            TALLOC_CTX *mem_ctx, struct nbt_name_register *io)
     142             : {
     143          68 :         struct nbt_name_request *req = nbt_name_register_send(nbtsock, io);
     144          68 :         return nbt_name_register_recv(req, mem_ctx, io);
     145             : }
     146             : 
     147             : 
     148             : /*
     149             :   a 4 step broadcast registration. 3 lots of name registration requests, followed by
     150             :   a name registration demand
     151             : */
     152             : struct nbt_name_register_bcast_state {
     153             :         struct nbt_name_socket *nbtsock;
     154             :         struct nbt_name_register io;
     155             : };
     156             : 
     157             : static void nbt_name_register_bcast_handler(struct nbt_name_request *subreq);
     158             : 
     159             : /*
     160             :   the async send call for a 4 stage name registration
     161             : */
     162         389 : _PUBLIC_ struct tevent_req *nbt_name_register_bcast_send(TALLOC_CTX *mem_ctx,
     163             :                                         struct tevent_context *ev,
     164             :                                         struct nbt_name_socket *nbtsock,
     165             :                                         struct nbt_name_register_bcast *io)
     166             : {
     167          12 :         struct tevent_req *req;
     168          12 :         struct nbt_name_register_bcast_state *state;
     169          12 :         struct nbt_name_request *subreq;
     170             : 
     171         389 :         req = tevent_req_create(mem_ctx, &state,
     172             :                                 struct nbt_name_register_bcast_state);
     173         389 :         if (req == NULL) {
     174           0 :                 return NULL;
     175             :         }
     176             : 
     177         389 :         state->io.in.name            = io->in.name;
     178         389 :         state->io.in.dest_addr       = io->in.dest_addr;
     179         389 :         state->io.in.dest_port       = io->in.dest_port;
     180         389 :         state->io.in.address         = io->in.address;
     181         389 :         state->io.in.nb_flags        = io->in.nb_flags;
     182         389 :         state->io.in.register_demand = false;
     183         389 :         state->io.in.broadcast       = true;
     184         389 :         state->io.in.multi_homed     = false;
     185         389 :         state->io.in.ttl             = io->in.ttl;
     186         389 :         state->io.in.timeout         = 1;
     187         389 :         state->io.in.retries         = 2;
     188             : 
     189         389 :         state->nbtsock = nbtsock;
     190             : 
     191         389 :         subreq = nbt_name_register_send(nbtsock, &state->io);
     192         389 :         if (tevent_req_nomem(subreq, req)) {
     193           0 :                 return tevent_req_post(req, ev);
     194             :         }
     195             : 
     196         389 :         subreq->async.fn = nbt_name_register_bcast_handler;
     197         389 :         subreq->async.private_data = req;
     198             : 
     199         389 :         return req;
     200             : }
     201             : 
     202         772 : static void nbt_name_register_bcast_handler(struct nbt_name_request *subreq)
     203             : {
     204          23 :         struct tevent_req *req =
     205         772 :                 talloc_get_type_abort(subreq->async.private_data,
     206             :                 struct tevent_req);
     207          23 :         struct nbt_name_register_bcast_state *state =
     208         772 :                 tevent_req_data(req,
     209             :                 struct nbt_name_register_bcast_state);
     210          23 :         NTSTATUS status;
     211             : 
     212         772 :         status = nbt_name_register_recv(subreq, state, &state->io);
     213         772 :         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
     214         766 :                 if (state->io.in.register_demand == true) {
     215         383 :                         tevent_req_done(req);
     216         755 :                         return;
     217             :                 }
     218             : 
     219             :                 /* the registration timed out - good, send the demand */
     220         383 :                 state->io.in.register_demand = true;
     221         383 :                 state->io.in.retries         = 0;
     222             : 
     223         383 :                 subreq = nbt_name_register_send(state->nbtsock, &state->io);
     224         383 :                 if (tevent_req_nomem(subreq, req)) {
     225           0 :                         return;
     226             :                 }
     227             : 
     228         383 :                 subreq->async.fn = nbt_name_register_bcast_handler;
     229         383 :                 subreq->async.private_data = req;
     230         383 :                 return;
     231             :         }
     232             : 
     233           6 :         if (!NT_STATUS_IS_OK(status)) {
     234           0 :                 tevent_req_nterror(req, status);
     235           0 :                 return;
     236             :         }
     237             : 
     238           6 :         DEBUG(3,("Name registration conflict from %s for %s with ip %s - rcode %d\n",
     239             :                  state->io.out.reply_from,
     240             :                  nbt_name_string(state, &state->io.out.name),
     241             :                  state->io.out.reply_addr,
     242             :                  state->io.out.rcode));
     243             : 
     244           6 :         tevent_req_nterror(req, NT_STATUS_CONFLICTING_ADDRESSES);
     245             : }
     246             : 
     247             : /*
     248             :   broadcast 4 part name register - recv
     249             : */
     250         389 : _PUBLIC_ NTSTATUS nbt_name_register_bcast_recv(struct tevent_req *req)
     251             : {
     252          12 :         NTSTATUS status;
     253             : 
     254         389 :         if (tevent_req_is_nterror(req, &status)) {
     255           6 :                 tevent_req_received(req);
     256           6 :                 return status;
     257             :         }
     258             : 
     259         383 :         tevent_req_received(req);
     260         383 :         return NT_STATUS_OK;
     261             : }
     262             : 
     263             : /*
     264             :   broadcast 4 part name register - sync interface
     265             : */
     266           0 : NTSTATUS nbt_name_register_bcast(struct nbt_name_socket *nbtsock,
     267             :                                  struct nbt_name_register_bcast *io)
     268             : {
     269           0 :         TALLOC_CTX *frame = talloc_stackframe();
     270           0 :         struct tevent_context *ev;
     271           0 :         struct tevent_req *subreq;
     272           0 :         NTSTATUS status;
     273             : 
     274             :         /*
     275             :          * TODO: create a temporary event context
     276             :          */
     277           0 :         ev = nbtsock->event_ctx;
     278             : 
     279           0 :         subreq = nbt_name_register_bcast_send(frame, ev, nbtsock, io);
     280           0 :         if (subreq == NULL) {
     281           0 :                 talloc_free(frame);
     282           0 :                 return NT_STATUS_NO_MEMORY;
     283             :         }
     284             : 
     285           0 :         if (!tevent_req_poll(subreq, ev)) {
     286           0 :                 status = map_nt_error_from_unix_common(errno);
     287           0 :                 talloc_free(frame);
     288           0 :                 return status;
     289             :         }
     290             : 
     291           0 :         status = nbt_name_register_bcast_recv(subreq);
     292           0 :         if (!NT_STATUS_IS_OK(status)) {
     293           0 :                 talloc_free(frame);
     294           0 :                 return status;
     295             :         }
     296             : 
     297           0 :         TALLOC_FREE(frame);
     298           0 :         return NT_STATUS_OK;
     299             : }
     300             : 
     301             : 
     302             : /*
     303             :   a wins name register with multiple WINS servers and multiple
     304             :   addresses to register. Try each WINS server in turn, until we get a
     305             :   reply for each address
     306             : */
     307             : struct nbt_name_register_wins_state {
     308             :         struct nbt_name_socket *nbtsock;
     309             :         struct nbt_name_register io;
     310             :         char **wins_servers;
     311             :         uint16_t wins_port;
     312             :         char **addresses;
     313             :         uint32_t address_idx;
     314             : };
     315             : 
     316             : static void nbt_name_register_wins_handler(struct nbt_name_request *subreq);
     317             : 
     318             : /*
     319             :   the async send call for a multi-server WINS register
     320             : */
     321         418 : _PUBLIC_ struct tevent_req *nbt_name_register_wins_send(TALLOC_CTX *mem_ctx,
     322             :                                                 struct tevent_context *ev,
     323             :                                                 struct nbt_name_socket *nbtsock,
     324             :                                                 struct nbt_name_register_wins *io)
     325             : {
     326          12 :         struct tevent_req *req;
     327          12 :         struct nbt_name_register_wins_state *state;
     328          12 :         struct nbt_name_request *subreq;
     329             : 
     330         418 :         req = tevent_req_create(mem_ctx, &state,
     331             :                                 struct nbt_name_register_wins_state);
     332         418 :         if (req == NULL) {
     333           0 :                 return NULL;
     334             :         }
     335             : 
     336         418 :         if (io->in.wins_servers == NULL) {
     337           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     338           0 :                 return tevent_req_post(req, ev);
     339             :         }
     340             : 
     341         418 :         if (io->in.wins_servers[0] == NULL) {
     342           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     343           0 :                 return tevent_req_post(req, ev);
     344             :         }
     345             : 
     346         418 :         if (io->in.addresses == NULL) {
     347           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     348           0 :                 return tevent_req_post(req, ev);
     349             :         }
     350             : 
     351         418 :         if (io->in.addresses[0] == NULL) {
     352           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     353           0 :                 return tevent_req_post(req, ev);
     354             :         }
     355             : 
     356         418 :         state->wins_port = io->in.wins_port;
     357         418 :         state->wins_servers = str_list_copy(state, io->in.wins_servers);
     358         418 :         if (tevent_req_nomem(state->wins_servers, req)) {
     359           0 :                 return tevent_req_post(req, ev);
     360             :         }
     361             : 
     362         418 :         state->addresses = str_list_copy(state, io->in.addresses);
     363         418 :         if (tevent_req_nomem(state->addresses, req)) {
     364           0 :                 return tevent_req_post(req, ev);
     365             :         }
     366             : 
     367         418 :         state->io.in.name            = io->in.name;
     368         418 :         state->io.in.dest_addr       = state->wins_servers[0];
     369         418 :         state->io.in.dest_port       = state->wins_port;
     370         418 :         state->io.in.address         = io->in.addresses[0];
     371         418 :         state->io.in.nb_flags        = io->in.nb_flags;
     372         418 :         state->io.in.broadcast       = false;
     373         418 :         state->io.in.register_demand = false;
     374         418 :         state->io.in.multi_homed     = (io->in.nb_flags & NBT_NM_GROUP)?false:true;
     375         418 :         state->io.in.ttl             = io->in.ttl;
     376         418 :         state->io.in.timeout         = 3;
     377         418 :         state->io.in.retries         = 2;
     378             : 
     379         418 :         state->nbtsock     = nbtsock;
     380         418 :         state->address_idx = 0;
     381             : 
     382         418 :         subreq = nbt_name_register_send(nbtsock, &state->io);
     383         418 :         if (tevent_req_nomem(subreq, req)) {
     384           0 :                 return tevent_req_post(req, ev);
     385             :         }
     386             : 
     387         418 :         subreq->async.fn = nbt_name_register_wins_handler;
     388         418 :         subreq->async.private_data = req;
     389             : 
     390         418 :         return req;
     391             : }
     392             : 
     393             : /*
     394             :   state handler for WINS multi-homed multi-server name register
     395             : */
     396         418 : static void nbt_name_register_wins_handler(struct nbt_name_request *subreq)
     397             : {
     398          12 :         struct tevent_req *req =
     399         418 :                 talloc_get_type_abort(subreq->async.private_data,
     400             :                 struct tevent_req);
     401          12 :         struct nbt_name_register_wins_state *state =
     402         418 :                 tevent_req_data(req,
     403             :                 struct nbt_name_register_wins_state);
     404          12 :         NTSTATUS status;
     405             : 
     406         418 :         status = nbt_name_register_recv(subreq, state, &state->io);
     407         418 :         if (NT_STATUS_EQUAL(status, NT_STATUS_IO_TIMEOUT)) {
     408             :                 /* the register timed out - try the next WINS server */
     409           0 :                 state->wins_servers++;
     410           0 :                 if (state->wins_servers[0] == NULL) {
     411           0 :                         tevent_req_nterror(req, status);
     412           0 :                         return;
     413             :                 }
     414             : 
     415           0 :                 state->address_idx = 0;
     416           0 :                 state->io.in.dest_addr = state->wins_servers[0];
     417           0 :                 state->io.in.dest_port = state->wins_port;
     418           0 :                 state->io.in.address   = state->addresses[0];
     419             : 
     420           0 :                 subreq = nbt_name_register_send(state->nbtsock, &state->io);
     421           0 :                 if (tevent_req_nomem(subreq, req)) {
     422           0 :                         return;
     423             :                 }
     424             : 
     425           0 :                 subreq->async.fn = nbt_name_register_wins_handler;
     426           0 :                 subreq->async.private_data = req;
     427           0 :                 return;
     428             :         }
     429             : 
     430         418 :         if (!NT_STATUS_IS_OK(status)) {
     431         389 :                 tevent_req_nterror(req, status);
     432         389 :                 return;
     433             :         }
     434             : 
     435          29 :         if (state->io.out.rcode == 0 &&
     436          27 :             state->addresses[state->address_idx+1] != NULL) {
     437             :                 /* register our next address */
     438           0 :                 state->io.in.address = state->addresses[++(state->address_idx)];
     439             : 
     440           0 :                 subreq = nbt_name_register_send(state->nbtsock, &state->io);
     441           0 :                 if (tevent_req_nomem(subreq, req)) {
     442           0 :                         return;
     443             :                 }
     444             : 
     445           0 :                 subreq->async.fn = nbt_name_register_wins_handler;
     446           0 :                 subreq->async.private_data = req;
     447           0 :                 return;
     448             :         }
     449             : 
     450          29 :         tevent_req_done(req);
     451             : }
     452             : 
     453             : /*
     454             :   multi-homed WINS name register - recv side
     455             : */
     456         418 : _PUBLIC_ NTSTATUS nbt_name_register_wins_recv(struct tevent_req *req,
     457             :                                               TALLOC_CTX *mem_ctx,
     458             :                                               struct nbt_name_register_wins *io)
     459             : {
     460          12 :         struct nbt_name_register_wins_state *state =
     461         418 :                 tevent_req_data(req,
     462             :                 struct nbt_name_register_wins_state);
     463          12 :         NTSTATUS status;
     464             : 
     465         418 :         if (tevent_req_is_nterror(req, &status)) {
     466         389 :                 tevent_req_received(req);
     467         389 :                 return status;
     468             :         }
     469             : 
     470          29 :         io->out.wins_server = talloc_move(mem_ctx, &state->wins_servers[0]);
     471          29 :         io->out.rcode = state->io.out.rcode;
     472             : 
     473          29 :         tevent_req_received(req);
     474          29 :         return NT_STATUS_OK;
     475             : }
     476             : 
     477             : /*
     478             :   multi-homed WINS register - sync interface
     479             : */
     480          29 : _PUBLIC_ NTSTATUS nbt_name_register_wins(struct nbt_name_socket *nbtsock,
     481             :                                 TALLOC_CTX *mem_ctx,
     482             :                                 struct nbt_name_register_wins *io)
     483             : {
     484          29 :         TALLOC_CTX *frame = talloc_stackframe();
     485           0 :         struct tevent_context *ev;
     486           0 :         struct tevent_req *subreq;
     487           0 :         NTSTATUS status;
     488             : 
     489             :         /*
     490             :          * TODO: create a temporary event context
     491             :          */
     492          29 :         ev = nbtsock->event_ctx;
     493             : 
     494          29 :         subreq = nbt_name_register_wins_send(frame, ev, nbtsock, io);
     495          29 :         if (subreq == NULL) {
     496           0 :                 talloc_free(frame);
     497           0 :                 return NT_STATUS_NO_MEMORY;
     498             :         }
     499             : 
     500          29 :         if (!tevent_req_poll(subreq, ev)) {
     501           0 :                 status = map_nt_error_from_unix_common(errno);
     502           0 :                 talloc_free(frame);
     503           0 :                 return status;
     504             :         }
     505             : 
     506          29 :         status = nbt_name_register_wins_recv(subreq, mem_ctx, io);
     507          29 :         if (!NT_STATUS_IS_OK(status)) {
     508           0 :                 talloc_free(frame);
     509           0 :                 return status;
     510             :         }
     511             : 
     512          29 :         TALLOC_FREE(frame);
     513          29 :         return NT_STATUS_OK;
     514             : }

Generated by: LCOV version 1.14