LCOV - code coverage report
Current view: top level - source4/libcli/raw - clisocket.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 90 212 42.5 %
Date: 2024-04-21 15:09:00 Functions: 8 11 72.7 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             : 
       4             :    SMB client socket context management functions
       5             : 
       6             :    Copyright (C) Andrew Tridgell 1994-2005
       7             :    Copyright (C) James Myers 2003 <myersjj@samba.org>
       8             : 
       9             :    This program is free software; you can redistribute it and/or modify
      10             :    it under the terms of the GNU General Public License as published by
      11             :    the Free Software Foundation; either version 3 of the License, or
      12             :    (at your option) any later version.
      13             : 
      14             :    This program is distributed in the hope that it will be useful,
      15             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      16             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17             :    GNU General Public License for more details.
      18             : 
      19             :    You should have received a copy of the GNU General Public License
      20             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      21             : */
      22             : 
      23             : #include "includes.h"
      24             : #include "system/network.h"
      25             : #include "../lib/async_req/async_sock.h"
      26             : #include "../lib/util/tevent_ntstatus.h"
      27             : #include "lib/events/events.h"
      28             : #include "libcli/raw/libcliraw.h"
      29             : #include "libcli/composite/composite.h"
      30             : #include "lib/socket/socket.h"
      31             : #include "libcli/resolve/resolve.h"
      32             : #include "param/param.h"
      33             : #include "libcli/raw/raw_proto.h"
      34             : #include "../libcli/smb/read_smb.h"
      35             : 
      36             : struct smbcli_transport_connect_state {
      37             :         struct tevent_context *ev;
      38             :         struct socket_context *sock;
      39             :         struct tevent_req *io_req;
      40             :         uint8_t *request;
      41             :         struct iovec iov;
      42             :         uint8_t *response;
      43             : };
      44             : 
      45             : static void smbcli_transport_connect_cleanup(struct tevent_req *req,
      46             :                                              enum tevent_req_state req_state);
      47             : static void smbcli_transport_connect_writev_done(struct tevent_req *subreq);
      48             : static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq);
      49             : 
      50       15578 : static struct tevent_req *smbcli_transport_connect_send(TALLOC_CTX *mem_ctx,
      51             :                                                  struct tevent_context *ev,
      52             :                                                  struct socket_context *sock,
      53             :                                                  uint16_t port,
      54             :                                                  uint32_t timeout_msec,
      55             :                                                  struct nbt_name *calling,
      56             :                                                  struct nbt_name *called)
      57             : {
      58         842 :         struct tevent_req *req;
      59         842 :         struct smbcli_transport_connect_state *state;
      60         842 :         struct tevent_req *subreq;
      61         842 :         DATA_BLOB calling_blob, called_blob;
      62         842 :         uint8_t *p;
      63         842 :         NTSTATUS status;
      64             : 
      65       15578 :         req = tevent_req_create(mem_ctx, &state,
      66             :                                 struct smbcli_transport_connect_state);
      67       15578 :         if (req == NULL) {
      68           0 :                 return NULL;
      69             :         }
      70       15578 :         state->ev = ev;
      71       15578 :         state->sock = sock;
      72             : 
      73       15578 :         if (port != 139) {
      74       15578 :                 tevent_req_done(req);
      75       15578 :                 return tevent_req_post(req, ev);
      76             :         }
      77             : 
      78           0 :         tevent_req_set_cleanup_fn(req, smbcli_transport_connect_cleanup);
      79             : 
      80           0 :         status = nbt_name_to_blob(state, &calling_blob, calling);
      81           0 :         if (tevent_req_nterror(req, status)) {
      82           0 :                 return tevent_req_post(req, ev);
      83             :         }
      84             : 
      85           0 :         status = nbt_name_to_blob(state, &called_blob, called);
      86           0 :         if (tevent_req_nterror(req, status)) {
      87           0 :                 return tevent_req_post(req, ev);
      88             :         }
      89             : 
      90           0 :         state->request = talloc_array(state, uint8_t,
      91             :                                       NBT_HDR_SIZE +
      92             :                                       called_blob.length +
      93             :                                       calling_blob.length);
      94           0 :         if (tevent_req_nomem(state->request, req)) {
      95           0 :                 return tevent_req_post(req, ev);
      96             :         }
      97             : 
      98             :         /* put in the destination name */
      99           0 :         p = state->request + NBT_HDR_SIZE;
     100           0 :         memcpy(p, called_blob.data, called_blob.length);
     101           0 :         p += called_blob.length;
     102             : 
     103           0 :         memcpy(p, calling_blob.data, calling_blob.length);
     104           0 :         p += calling_blob.length;
     105             : 
     106           0 :         _smb_setlen_nbt(state->request,
     107             :                         PTR_DIFF(p, state->request) - NBT_HDR_SIZE);
     108           0 :         SCVAL(state->request, 0, NBSSrequest);
     109             : 
     110           0 :         state->iov.iov_len = talloc_array_length(state->request);
     111           0 :         state->iov.iov_base = (void *)state->request;
     112             : 
     113           0 :         subreq = writev_send(state, ev, NULL,
     114             :                              sock->fd,
     115             :                              true, /* err_on_readability */
     116           0 :                              &state->iov, 1);
     117           0 :         if (tevent_req_nomem(subreq, req)) {
     118           0 :                 return tevent_req_post(req, ev);
     119             :         }
     120           0 :         tevent_req_set_callback(subreq,
     121             :                                 smbcli_transport_connect_writev_done,
     122             :                                 req);
     123           0 :         state->io_req = subreq;
     124             : 
     125           0 :         if (timeout_msec > 0) {
     126           0 :                 struct timeval endtime;
     127             : 
     128           0 :                 endtime = timeval_current_ofs_msec(timeout_msec);
     129           0 :                 if (!tevent_req_set_endtime(req, ev, endtime)) {
     130           0 :                         return tevent_req_post(req, ev);
     131             :                 }
     132             :         }
     133             : 
     134           0 :         return req;
     135             : }
     136             : 
     137           0 : static void smbcli_transport_connect_cleanup(struct tevent_req *req,
     138             :                                              enum tevent_req_state req_state)
     139             : {
     140           0 :         struct smbcli_transport_connect_state *state =
     141           0 :                 tevent_req_data(req,
     142             :                 struct smbcli_transport_connect_state);
     143             : 
     144           0 :         TALLOC_FREE(state->io_req);
     145             : 
     146           0 :         if (state->sock == NULL) {
     147           0 :                 return;
     148             :         }
     149             : 
     150           0 :         if (state->sock->fd == -1) {
     151           0 :                 return;
     152             :         }
     153             : 
     154           0 :         if (req_state == TEVENT_REQ_DONE) {
     155             :                 /*
     156             :                  * we keep the socket open for the caller to use
     157             :                  */
     158           0 :                 state->sock = NULL;
     159           0 :                 return;
     160             :         }
     161             : 
     162           0 :         close(state->sock->fd);
     163           0 :         state->sock->fd = -1;
     164           0 :         state->sock = NULL;
     165             : }
     166             : 
     167           0 : static void smbcli_transport_connect_writev_done(struct tevent_req *subreq)
     168             : {
     169           0 :         struct tevent_req *req =
     170           0 :                 tevent_req_callback_data(subreq,
     171             :                 struct tevent_req);
     172           0 :         struct smbcli_transport_connect_state *state =
     173           0 :                 tevent_req_data(req,
     174             :                 struct smbcli_transport_connect_state);
     175           0 :         ssize_t ret;
     176           0 :         int err;
     177             : 
     178           0 :         state->io_req = NULL;
     179             : 
     180           0 :         ret = writev_recv(subreq, &err);
     181           0 :         TALLOC_FREE(subreq);
     182           0 :         if (ret == -1) {
     183           0 :                 NTSTATUS status = map_nt_error_from_unix_common(err);
     184           0 :                 tevent_req_nterror(req, status);
     185           0 :                 return;
     186             :         }
     187             : 
     188           0 :         subreq = read_smb_send(state, state->ev,
     189           0 :                                state->sock->fd);
     190           0 :         if (tevent_req_nomem(subreq, req)) {
     191           0 :                 return;
     192             :         }
     193           0 :         tevent_req_set_callback(subreq,
     194             :                                 smbcli_transport_connect_read_smb_done,
     195             :                                 req);
     196           0 :         state->io_req = subreq;
     197             : }
     198             : 
     199           0 : static void smbcli_transport_connect_read_smb_done(struct tevent_req *subreq)
     200             : {
     201           0 :         struct tevent_req *req =
     202           0 :                 tevent_req_callback_data(subreq,
     203             :                 struct tevent_req);
     204           0 :         struct smbcli_transport_connect_state *state =
     205           0 :                 tevent_req_data(req,
     206             :                 struct smbcli_transport_connect_state);
     207           0 :         ssize_t ret;
     208           0 :         int err;
     209           0 :         NTSTATUS status;
     210           0 :         uint8_t error;
     211             : 
     212           0 :         state->io_req = NULL;
     213             : 
     214           0 :         ret = read_smb_recv(subreq, state,
     215             :                             &state->response, &err);
     216           0 :         TALLOC_FREE(subreq);
     217           0 :         if (ret == -1) {
     218           0 :                 status = map_nt_error_from_unix_common(err);
     219           0 :                 tevent_req_nterror(req, status);
     220           0 :                 return;
     221             :         }
     222             : 
     223           0 :         if (ret < 4) {
     224           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     225           0 :                 return;
     226             :         }
     227             : 
     228           0 :         switch (CVAL(state->response, 0)) {
     229           0 :         case NBSSpositive:
     230           0 :                 tevent_req_done(req);
     231           0 :                 return;
     232             : 
     233           0 :         case NBSSnegative:
     234           0 :                 if (ret < 5) {
     235           0 :                         tevent_req_nterror(req, NT_STATUS_INVALID_NETWORK_RESPONSE);
     236           0 :                         return;
     237             :                 }
     238             : 
     239           0 :                 error = CVAL(state->response, 4);
     240           0 :                 switch (error) {
     241           0 :                 case 0x80:
     242             :                 case 0x81:
     243           0 :                         status = NT_STATUS_REMOTE_NOT_LISTENING;
     244           0 :                         break;
     245           0 :                 case 0x82:
     246           0 :                         status = NT_STATUS_RESOURCE_NAME_NOT_FOUND;
     247           0 :                         break;
     248           0 :                 case 0x83:
     249           0 :                         status = NT_STATUS_REMOTE_RESOURCES;
     250           0 :                         break;
     251           0 :                 default:
     252           0 :                         status = NT_STATUS_INVALID_NETWORK_RESPONSE;
     253           0 :                         break;
     254             :                 }
     255           0 :                 break;
     256             : 
     257           0 :         case NBSSretarget:
     258           0 :                 DEBUG(1,("Warning: session retarget not supported\n"));
     259           0 :                 status = NT_STATUS_NOT_SUPPORTED;
     260           0 :                 break;
     261             : 
     262           0 :         default:
     263           0 :                 status = NT_STATUS_INVALID_NETWORK_RESPONSE;
     264           0 :                 break;
     265             :         }
     266             : 
     267           0 :         tevent_req_nterror(req, status);
     268             : }
     269             : 
     270       15578 : static NTSTATUS smbcli_transport_connect_recv(struct tevent_req *req)
     271             : {
     272       15578 :         return tevent_req_simple_recv_ntstatus(req);
     273             : }
     274             : 
     275             : struct sock_connect_state {
     276             :         struct composite_context *ctx;
     277             :         const char *host_name;
     278             :         int num_ports;
     279             :         uint16_t *ports;
     280             :         const char *socket_options;
     281             :         struct smbcli_socket *result;
     282             :         struct socket_connect_multi_ex multi_ex;
     283             :         struct nbt_name calling;
     284             :         struct nbt_name called;
     285             : };
     286             : 
     287             : /*
     288             :   connect a smbcli_socket context to an IP/port pair
     289             :   if port is 0 then choose 445 then 139
     290             : */
     291             : 
     292       15578 : static struct tevent_req *smbcli_sock_establish_send(TALLOC_CTX *mem_ctx,
     293             :                                                      struct tevent_context *ev,
     294             :                                                      struct socket_context *sock,
     295             :                                                      struct socket_address *addr,
     296             :                                                      void *private_data)
     297             : {
     298         842 :         struct sock_connect_state *state =
     299       15578 :                 talloc_get_type_abort(private_data,
     300             :                 struct sock_connect_state);
     301       15578 :         uint32_t timeout_msec = 15 * 1000;
     302             : 
     303       31156 :         return smbcli_transport_connect_send(state,
     304             :                                              ev,
     305             :                                              sock,
     306       15578 :                                              addr->port,
     307             :                                              timeout_msec,
     308             :                                              &state->calling,
     309             :                                              &state->called);
     310             : }
     311             : 
     312       15578 : static NTSTATUS smbcli_sock_establish_recv(struct tevent_req *req)
     313             : {
     314       15578 :         return smbcli_transport_connect_recv(req);
     315             : }
     316             : 
     317             : static void smbcli_sock_connect_recv_conn(struct composite_context *ctx);
     318             : 
     319       15579 : struct composite_context *smbcli_sock_connect_send(TALLOC_CTX *mem_ctx,
     320             :                                                    const char *host_addr,
     321             :                                                    const char **ports,
     322             :                                                    const char *host_name,
     323             :                                                    struct resolve_context *resolve_ctx,
     324             :                                                    struct tevent_context *event_ctx,
     325             :                                                    const char *socket_options,
     326             :                                                    struct nbt_name *calling,
     327             :                                                    struct nbt_name *called)
     328             : {
     329         842 :         struct composite_context *result, *ctx;
     330         842 :         struct sock_connect_state *state;
     331         842 :         NTSTATUS status;
     332         842 :         int i;
     333             : 
     334       15579 :         result = talloc_zero(mem_ctx, struct composite_context);
     335       15579 :         if (result == NULL) goto failed;
     336       15579 :         result->state = COMPOSITE_STATE_IN_PROGRESS;
     337             : 
     338       15579 :         result->event_ctx = event_ctx;
     339       15579 :         if (result->event_ctx == NULL) goto failed;
     340             : 
     341       15579 :         state = talloc(result, struct sock_connect_state);
     342       15579 :         if (state == NULL) goto failed;
     343       15579 :         state->ctx = result;
     344       15579 :         result->private_data = state;
     345             : 
     346       15579 :         state->host_name = talloc_strdup(state, host_name);
     347       15579 :         if (state->host_name == NULL) goto failed;
     348             : 
     349       15579 :         state->num_ports = str_list_length(ports);
     350       15579 :         state->ports = talloc_array(state, uint16_t, state->num_ports);
     351       15579 :         if (state->ports == NULL) goto failed;
     352       46737 :         for (i=0;ports[i];i++) {
     353       31158 :                 state->ports[i] = atoi(ports[i]);
     354             :         }
     355       15579 :         state->socket_options = talloc_reference(state, socket_options);
     356             : 
     357       15579 :         if (!host_addr) {
     358       14792 :                 host_addr = host_name;
     359             :         }
     360             : 
     361       15579 :         state->multi_ex.private_data = state;
     362       15579 :         state->multi_ex.establish_send = smbcli_sock_establish_send;
     363       15579 :         state->multi_ex.establish_recv = smbcli_sock_establish_recv;
     364             : 
     365       15579 :         status = nbt_name_dup(state, calling, &state->calling);
     366       15579 :         if (!NT_STATUS_IS_OK(status)) {
     367           0 :                 goto failed;
     368             :         }
     369       15579 :         status = nbt_name_dup(state, called, &state->called);
     370       15579 :         if (!NT_STATUS_IS_OK(status)) {
     371           0 :                 goto failed;
     372             :         }
     373             : 
     374       16421 :         ctx = socket_connect_multi_ex_send(state, host_addr,
     375             :                                            state->num_ports, state->ports,
     376             :                                            resolve_ctx,
     377       15579 :                                            state->ctx->event_ctx,
     378             :                                            &state->multi_ex);
     379       15579 :         if (ctx == NULL) goto failed;
     380       15579 :         ctx->async.fn = smbcli_sock_connect_recv_conn;
     381       15579 :         ctx->async.private_data = state;
     382       15579 :         return result;
     383             : 
     384           0 : failed:
     385           0 :         talloc_free(result);
     386           0 :         return NULL;
     387             : }
     388             : 
     389       15579 : static void smbcli_sock_connect_recv_conn(struct composite_context *ctx)
     390             : {
     391         842 :         struct sock_connect_state *state =
     392       15579 :                 talloc_get_type(ctx->async.private_data,
     393             :                                 struct sock_connect_state);
     394         842 :         struct socket_context *sock;
     395         842 :         uint16_t port;
     396             : 
     397       15579 :         state->ctx->status = socket_connect_multi_ex_recv(ctx, state, &sock,
     398             :                                                           &port);
     399       15579 :         if (!composite_is_ok(state->ctx)) return;
     400             : 
     401       15578 :         state->ctx->status =
     402       15578 :                 socket_set_option(sock, state->socket_options, NULL);
     403       15578 :         if (!composite_is_ok(state->ctx)) return;
     404             : 
     405             : 
     406       15578 :         state->result = talloc_zero(state, struct smbcli_socket);
     407       15578 :         if (composite_nomem(state->result, state->ctx)) return;
     408             : 
     409       15578 :         state->result->sock = talloc_steal(state->result, sock);
     410       15578 :         state->result->port = port;
     411       15578 :         state->result->hostname = talloc_steal(sock, state->host_name);
     412             : 
     413       15578 :         state->result->event.ctx = state->ctx->event_ctx;
     414       15578 :         if (composite_nomem(state->result->event.ctx, state->ctx)) return;
     415             : 
     416       15578 :         composite_done(state->ctx);
     417             : }
     418             : 
     419             : /*
     420             :   finish a smbcli_sock_connect_send() operation
     421             : */
     422       15579 : NTSTATUS smbcli_sock_connect_recv(struct composite_context *c,
     423             :                                   TALLOC_CTX *mem_ctx,
     424             :                                   struct smbcli_socket **result)
     425             : {
     426       15579 :         NTSTATUS status = composite_wait(c);
     427       15579 :         if (NT_STATUS_IS_OK(status)) {
     428         842 :                 struct sock_connect_state *state =
     429       15578 :                         talloc_get_type(c->private_data,
     430             :                                         struct sock_connect_state);
     431       15578 :                 *result = talloc_steal(mem_ctx, state->result);
     432             :         }
     433       15579 :         talloc_free(c);
     434       15579 :         return status;
     435             : }
     436             : 
     437             : /*
     438             :   connect a smbcli_socket context to an IP/port pair
     439             :   if port is 0 then choose the ports listed in smb.conf (normally 445 then 139)
     440             : 
     441             :   sync version of the function
     442             : */
     443           6 : NTSTATUS smbcli_sock_connect(TALLOC_CTX *mem_ctx,
     444             :                              const char *host_addr, const char **ports,
     445             :                              const char *host_name,
     446             :                              struct resolve_context *resolve_ctx,
     447             :                              struct tevent_context *event_ctx,
     448             :                              const char *socket_options,
     449             :                              struct nbt_name *calling,
     450             :                              struct nbt_name *called,
     451             :                              struct smbcli_socket **result)
     452             : {
     453           0 :         struct composite_context *c =
     454           6 :                 smbcli_sock_connect_send(mem_ctx, host_addr, ports, host_name,
     455             :                                          resolve_ctx,
     456             :                                          event_ctx, socket_options,
     457             :                                          calling, called);
     458           6 :         return smbcli_sock_connect_recv(c, mem_ctx, result);
     459             : }

Generated by: LCOV version 1.14