LCOV - code coverage report
Current view: top level - source3/libsmb - smbsock_connect.c (source / functions) Hit Total Coverage
Test: coverage report for fix-15632 9995c5c2 Lines: 306 416 73.6 %
Date: 2024-04-13 12:30:31 Functions: 22 22 100.0 %

          Line data    Source code
       1             : /*
       2             :    Unix SMB/CIFS implementation.
       3             :    Connect to 445 and 139/nbsesssetup
       4             :    Copyright (C) Volker Lendecke 2010
       5             : 
       6             :    This program is free software; you can redistribute it and/or modify
       7             :    it under the terms of the GNU General Public License as published by
       8             :    the Free Software Foundation; either version 3 of the License, or
       9             :    (at your option) any later version.
      10             : 
      11             :    This program is distributed in the hope that it will be useful,
      12             :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      13             :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      14             :    GNU General Public License for more details.
      15             : 
      16             :    You should have received a copy of the GNU General Public License
      17             :    along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "includes.h"
      21             : #include "../lib/async_req/async_sock.h"
      22             : #include "../lib/util/tevent_ntstatus.h"
      23             : #include "../lib/util/tevent_unix.h"
      24             : #include "client.h"
      25             : #include "async_smb.h"
      26             : #include "../libcli/smb/read_smb.h"
      27             : #include "libsmb/nmblib.h"
      28             : 
      29             : struct cli_session_request_state {
      30             :         struct tevent_context *ev;
      31             :         int sock;
      32             :         uint32_t len_hdr;
      33             :         struct iovec iov[3];
      34             :         uint8_t nb_session_response;
      35             : };
      36             : 
      37             : static void cli_session_request_sent(struct tevent_req *subreq);
      38             : static void cli_session_request_recvd(struct tevent_req *subreq);
      39             : 
      40        1041 : static struct tevent_req *cli_session_request_send(TALLOC_CTX *mem_ctx,
      41             :                                         struct tevent_context *ev,
      42             :                                         int sock,
      43             :                                         const struct nmb_name *called,
      44             :                                         const struct nmb_name *calling)
      45             : {
      46           0 :         struct tevent_req *req, *subreq;
      47           0 :         struct cli_session_request_state *state;
      48             : 
      49        1041 :         req = tevent_req_create(mem_ctx, &state,
      50             :                                 struct cli_session_request_state);
      51        1041 :         if (req == NULL) {
      52           0 :                 return NULL;
      53             :         }
      54        1041 :         state->ev = ev;
      55        1041 :         state->sock = sock;
      56             : 
      57        2082 :         state->iov[1].iov_base = name_mangle(
      58        1041 :                 state, called->name, called->name_type);
      59        1041 :         if (tevent_req_nomem(state->iov[1].iov_base, req)) {
      60           0 :                 return tevent_req_post(req, ev);
      61             :         }
      62        3123 :         state->iov[1].iov_len = name_len(
      63        1041 :                 (unsigned char *)state->iov[1].iov_base,
      64        1041 :                 talloc_get_size(state->iov[1].iov_base));
      65             : 
      66        2082 :         state->iov[2].iov_base = name_mangle(
      67        1041 :                 state, calling->name, calling->name_type);
      68        1041 :         if (tevent_req_nomem(state->iov[2].iov_base, req)) {
      69           0 :                 return tevent_req_post(req, ev);
      70             :         }
      71        3123 :         state->iov[2].iov_len = name_len(
      72        1041 :                 (unsigned char *)state->iov[2].iov_base,
      73        1041 :                 talloc_get_size(state->iov[2].iov_base));
      74             : 
      75        1041 :         _smb_setlen(((char *)&state->len_hdr),
      76             :                     state->iov[1].iov_len + state->iov[2].iov_len);
      77        1041 :         SCVAL((char *)&state->len_hdr, 0, 0x81);
      78             : 
      79        1041 :         state->iov[0].iov_base = &state->len_hdr;
      80        1041 :         state->iov[0].iov_len = sizeof(state->len_hdr);
      81             : 
      82        1041 :         subreq = writev_send(state, ev, NULL, sock, true, state->iov, 3);
      83        1041 :         if (tevent_req_nomem(subreq, req)) {
      84           0 :                 return tevent_req_post(req, ev);
      85             :         }
      86        1041 :         tevent_req_set_callback(subreq, cli_session_request_sent, req);
      87        1041 :         return req;
      88             : }
      89             : 
      90        1041 : static void cli_session_request_sent(struct tevent_req *subreq)
      91             : {
      92        1041 :         struct tevent_req *req = tevent_req_callback_data(
      93             :                 subreq, struct tevent_req);
      94        1041 :         struct cli_session_request_state *state = tevent_req_data(
      95             :                 req, struct cli_session_request_state);
      96           0 :         ssize_t ret;
      97           0 :         int err;
      98             : 
      99        1041 :         ret = writev_recv(subreq, &err);
     100        1041 :         TALLOC_FREE(subreq);
     101        1041 :         if (ret == -1) {
     102           0 :                 tevent_req_error(req, err);
     103           0 :                 return;
     104             :         }
     105        1041 :         subreq = read_smb_send(state, state->ev, state->sock);
     106        1041 :         if (tevent_req_nomem(subreq, req)) {
     107           0 :                 return;
     108             :         }
     109        1041 :         tevent_req_set_callback(subreq, cli_session_request_recvd, req);
     110             : }
     111             : 
     112        1039 : static void cli_session_request_recvd(struct tevent_req *subreq)
     113             : {
     114        1039 :         struct tevent_req *req = tevent_req_callback_data(
     115             :                 subreq, struct tevent_req);
     116        1039 :         struct cli_session_request_state *state = tevent_req_data(
     117             :                 req, struct cli_session_request_state);
     118           0 :         uint8_t *buf;
     119           0 :         ssize_t ret;
     120           0 :         int err;
     121             : 
     122        1039 :         ret = read_smb_recv(subreq, talloc_tos(), &buf, &err);
     123        1039 :         TALLOC_FREE(subreq);
     124             : 
     125        1039 :         if (ret < 4) {
     126           0 :                 ret = -1;
     127           0 :                 err = EIO;
     128             :         }
     129        1039 :         if (ret == -1) {
     130           0 :                 tevent_req_error(req, err);
     131           0 :                 return;
     132             :         }
     133             :         /*
     134             :          * In case of an error there is more information in the data
     135             :          * portion according to RFC1002. We're not subtle enough to
     136             :          * respond to the different error conditions, so drop the
     137             :          * error info here.
     138             :          */
     139        1039 :         state->nb_session_response = CVAL(buf, 0);
     140        1039 :         tevent_req_done(req);
     141             : }
     142             : 
     143        1039 : static bool cli_session_request_recv(struct tevent_req *req, int *err, uint8_t *resp)
     144             : {
     145        1039 :         struct cli_session_request_state *state = tevent_req_data(
     146             :                 req, struct cli_session_request_state);
     147             : 
     148        1039 :         if (tevent_req_is_unix_error(req, err)) {
     149           0 :                 return false;
     150             :         }
     151        1039 :         *resp = state->nb_session_response;
     152        1039 :         return true;
     153             : }
     154             : 
     155             : struct nb_connect_state {
     156             :         struct tevent_context *ev;
     157             :         const struct sockaddr_storage *addr;
     158             :         const char *called_name;
     159             :         int sock;
     160             :         struct tevent_req *session_subreq;
     161             :         struct nmb_name called;
     162             :         struct nmb_name calling;
     163             : };
     164             : 
     165             : static void nb_connect_cleanup(struct tevent_req *req,
     166             :                                enum tevent_req_state req_state);
     167             : static void nb_connect_connected(struct tevent_req *subreq);
     168             : static void nb_connect_done(struct tevent_req *subreq);
     169             : 
     170        1043 : static struct tevent_req *nb_connect_send(TALLOC_CTX *mem_ctx,
     171             :                                           struct tevent_context *ev,
     172             :                                           const struct sockaddr_storage *addr,
     173             :                                           const char *called_name,
     174             :                                           int called_type,
     175             :                                           const char *calling_name,
     176             :                                           int calling_type)
     177             : {
     178           0 :         struct tevent_req *req, *subreq;
     179           0 :         struct nb_connect_state *state;
     180             : 
     181        1043 :         req = tevent_req_create(mem_ctx, &state, struct nb_connect_state);
     182        1043 :         if (req == NULL) {
     183           0 :                 return NULL;
     184             :         }
     185        1043 :         state->ev = ev;
     186        1043 :         state->called_name = called_name;
     187        1043 :         state->addr = addr;
     188             : 
     189        1043 :         state->sock = -1;
     190        1043 :         make_nmb_name(&state->called, called_name, called_type);
     191        1043 :         make_nmb_name(&state->calling, calling_name, calling_type);
     192             : 
     193        1043 :         tevent_req_set_cleanup_fn(req, nb_connect_cleanup);
     194             : 
     195        1043 :         subreq = open_socket_out_send(state, ev, addr, NBT_SMB_PORT, 5000);
     196        1043 :         if (tevent_req_nomem(subreq, req)) {
     197           0 :                 return tevent_req_post(req, ev);
     198             :         }
     199        1043 :         tevent_req_set_callback(subreq, nb_connect_connected, req);
     200        1043 :         return req;
     201             : }
     202             : 
     203        2084 : static void nb_connect_cleanup(struct tevent_req *req,
     204             :                                enum tevent_req_state req_state)
     205             : {
     206        2084 :         struct nb_connect_state *state = tevent_req_data(
     207             :                 req, struct nb_connect_state);
     208             : 
     209             :         /*
     210             :          * we need to free a pending request before closing the
     211             :          * socket, see bug #11141
     212             :          */
     213        2084 :         TALLOC_FREE(state->session_subreq);
     214             : 
     215        2084 :         if (req_state == TEVENT_REQ_DONE) {
     216             :                 /*
     217             :                  * we keep the socket open for the caller to use
     218             :                  */
     219        1039 :                 return;
     220             :         }
     221             : 
     222        1045 :         if (state->sock != -1) {
     223           2 :                 close(state->sock);
     224           2 :                 state->sock = -1;
     225             :         }
     226             : 
     227        1045 :         return;
     228             : }
     229             : 
     230        1043 : static void nb_connect_connected(struct tevent_req *subreq)
     231             : {
     232        1043 :         struct tevent_req *req = tevent_req_callback_data(
     233             :                 subreq, struct tevent_req);
     234        1043 :         struct nb_connect_state *state = tevent_req_data(
     235             :                 req, struct nb_connect_state);
     236           0 :         NTSTATUS status;
     237             : 
     238        1043 :         status = open_socket_out_recv(subreq, &state->sock);
     239        1043 :         TALLOC_FREE(subreq);
     240        1043 :         if (tevent_req_nterror(req, status)) {
     241           2 :                 return;
     242             :         }
     243        1041 :         subreq = cli_session_request_send(state, state->ev, state->sock,
     244        1041 :                                           &state->called, &state->calling);
     245        1041 :         if (tevent_req_nomem(subreq, req)) {
     246           0 :                 return;
     247             :         }
     248        1041 :         tevent_req_set_callback(subreq, nb_connect_done, req);
     249        1041 :         state->session_subreq = subreq;
     250             : }
     251             : 
     252        1039 : static void nb_connect_done(struct tevent_req *subreq)
     253             : {
     254        1039 :         struct tevent_req *req = tevent_req_callback_data(
     255             :                 subreq, struct tevent_req);
     256        1039 :         struct nb_connect_state *state = tevent_req_data(
     257             :                 req, struct nb_connect_state);
     258           0 :         bool ret;
     259           0 :         int err;
     260           0 :         uint8_t resp;
     261             : 
     262        1039 :         state->session_subreq = NULL;
     263             : 
     264        1039 :         ret = cli_session_request_recv(subreq, &err, &resp);
     265        1039 :         TALLOC_FREE(subreq);
     266        1039 :         if (!ret) {
     267           0 :                 tevent_req_nterror(req, map_nt_error_from_unix(err));
     268           0 :                 return;
     269             :         }
     270             : 
     271             :         /*
     272             :          * RFC1002: 0x82 - POSITIVE SESSION RESPONSE
     273             :          */
     274             : 
     275        1039 :         if (resp != 0x82) {
     276             :                 /*
     277             :                  * The server did not like our session request
     278             :                  */
     279           0 :                 close(state->sock);
     280           0 :                 state->sock = -1;
     281             : 
     282           0 :                 if (strequal(state->called_name, "*SMBSERVER")) {
     283             :                         /*
     284             :                          * Here we could try a name status request and
     285             :                          * use the first 0x20 type name.
     286             :                          */
     287           0 :                         tevent_req_nterror(
     288             :                                 req, NT_STATUS_RESOURCE_NAME_NOT_FOUND);
     289           0 :                         return;
     290             :                 }
     291             : 
     292             :                 /*
     293             :                  * We could be subtle and distinguish between
     294             :                  * different failure modes, but what we do here
     295             :                  * instead is just retry with *SMBSERVER type 0x20.
     296             :                  */
     297           0 :                 state->called_name = "*SMBSERVER";
     298           0 :                 make_nmb_name(&state->called, state->called_name, 0x20);
     299             : 
     300           0 :                 subreq = open_socket_out_send(state, state->ev, state->addr,
     301             :                                               NBT_SMB_PORT, 5000);
     302           0 :                 if (tevent_req_nomem(subreq, req)) {
     303           0 :                         return;
     304             :                 }
     305           0 :                 tevent_req_set_callback(subreq, nb_connect_connected, req);
     306           0 :                 return;
     307             :         }
     308             : 
     309        1039 :         tevent_req_done(req);
     310        1039 :         return;
     311             : }
     312             : 
     313        1041 : static NTSTATUS nb_connect_recv(struct tevent_req *req, int *sock)
     314             : {
     315        1041 :         struct nb_connect_state *state = tevent_req_data(
     316             :                 req, struct nb_connect_state);
     317           0 :         NTSTATUS status;
     318             : 
     319        1041 :         if (tevent_req_is_nterror(req, &status)) {
     320           2 :                 tevent_req_received(req);
     321           2 :                 return status;
     322             :         }
     323        1039 :         *sock = state->sock;
     324        1039 :         state->sock = -1;
     325        1039 :         tevent_req_received(req);
     326        1039 :         return NT_STATUS_OK;
     327             : }
     328             : 
     329             : struct smbsock_connect_state {
     330             :         struct tevent_context *ev;
     331             :         const struct sockaddr_storage *addr;
     332             :         const char *called_name;
     333             :         uint8_t called_type;
     334             :         const char *calling_name;
     335             :         uint8_t calling_type;
     336             :         struct tevent_req *req_139;
     337             :         struct tevent_req *req_445;
     338             :         int sock;
     339             :         uint16_t port;
     340             : };
     341             : 
     342             : static void smbsock_connect_cleanup(struct tevent_req *req,
     343             :                                     enum tevent_req_state req_state);
     344             : static void smbsock_connect_connected(struct tevent_req *subreq);
     345             : static void smbsock_connect_do_139(struct tevent_req *subreq);
     346             : 
     347       17714 : struct tevent_req *smbsock_connect_send(TALLOC_CTX *mem_ctx,
     348             :                                         struct tevent_context *ev,
     349             :                                         const struct sockaddr_storage *addr,
     350             :                                         uint16_t port,
     351             :                                         const char *called_name,
     352             :                                         int called_type,
     353             :                                         const char *calling_name,
     354             :                                         int calling_type)
     355             : {
     356           0 :         struct tevent_req *req;
     357           0 :         struct smbsock_connect_state *state;
     358             : 
     359       17714 :         req = tevent_req_create(mem_ctx, &state, struct smbsock_connect_state);
     360       17714 :         if (req == NULL) {
     361           0 :                 return NULL;
     362             :         }
     363       17714 :         state->ev = ev;
     364       17714 :         state->addr = addr;
     365       17714 :         state->sock = -1;
     366       17714 :         state->called_name =
     367       17714 :                 (called_name != NULL) ? called_name : "*SMBSERVER";
     368       17714 :         state->called_type =
     369             :                 (called_type != -1) ? called_type : 0x20;
     370       17714 :         state->calling_name =
     371       17714 :                 (calling_name != NULL) ? calling_name : lp_netbios_name();
     372       17714 :         state->calling_type =
     373             :                 (calling_type != -1) ? calling_type : 0x00;
     374             : 
     375       17714 :         tevent_req_set_cleanup_fn(req, smbsock_connect_cleanup);
     376             : 
     377       17714 :         if (port == NBT_SMB_PORT) {
     378        1041 :                 if (lp_disable_netbios()) {
     379           0 :                         tevent_req_nterror(req, NT_STATUS_NOT_SUPPORTED);
     380           0 :                         return tevent_req_post(req, ev);
     381             :                 }
     382             : 
     383        2082 :                 state->req_139 = nb_connect_send(state, state->ev, state->addr,
     384        1041 :                                                  state->called_name,
     385        1041 :                                                  state->called_type,
     386        1041 :                                                  state->calling_name,
     387        1041 :                                                  state->calling_type);
     388        1041 :                 if (tevent_req_nomem(state->req_139, req)) {
     389           0 :                         return tevent_req_post(req, ev);
     390             :                 }
     391        1041 :                 tevent_req_set_callback(
     392             :                         state->req_139, smbsock_connect_connected, req);
     393        1041 :                 return req;
     394             :         }
     395       16673 :         if (port != 0) {
     396           0 :                 state->req_445 = open_socket_out_send(state, ev, addr, port,
     397             :                                                       5000);
     398           0 :                 if (tevent_req_nomem(state->req_445, req)) {
     399           0 :                         return tevent_req_post(req, ev);
     400             :                 }
     401           0 :                 tevent_req_set_callback(
     402             :                         state->req_445, smbsock_connect_connected, req);
     403           0 :                 return req;
     404             :         }
     405             : 
     406             :         /*
     407             :          * port==0, try both
     408             :          */
     409             : 
     410       16673 :         state->req_445 = open_socket_out_send(state, ev, addr, TCP_SMB_PORT, 5000);
     411       16673 :         if (tevent_req_nomem(state->req_445, req)) {
     412           0 :                 return tevent_req_post(req, ev);
     413             :         }
     414       16673 :         tevent_req_set_callback(state->req_445, smbsock_connect_connected,
     415             :                                 req);
     416             : 
     417             :         /*
     418             :          * Check for disable_netbios
     419             :          */
     420       16673 :         if (lp_disable_netbios()) {
     421           0 :                 return req;
     422             :         }
     423             : 
     424             :         /*
     425             :          * After 5 msecs, fire the 139 (NBT) request
     426             :          */
     427       16673 :         state->req_139 = tevent_wakeup_send(
     428             :                 state, ev, timeval_current_ofs(0, 5000));
     429       16673 :         if (tevent_req_nomem(state->req_139, req)) {
     430           0 :                 TALLOC_FREE(state->req_445);
     431           0 :                 return tevent_req_post(req, ev);
     432             :         }
     433       16673 :         tevent_req_set_callback(state->req_139, smbsock_connect_do_139,
     434             :                                 req);
     435       16673 :         return req;
     436             : }
     437             : 
     438       35426 : static void smbsock_connect_cleanup(struct tevent_req *req,
     439             :                                     enum tevent_req_state req_state)
     440             : {
     441       35426 :         struct smbsock_connect_state *state = tevent_req_data(
     442             :                 req, struct smbsock_connect_state);
     443             : 
     444             :         /*
     445             :          * we need to free a pending request before closing the
     446             :          * socket, see bug #11141
     447             :          */
     448       35426 :         TALLOC_FREE(state->req_445);
     449       35426 :         TALLOC_FREE(state->req_139);
     450             : 
     451       35426 :         if (req_state == TEVENT_REQ_DONE) {
     452             :                 /*
     453             :                  * we keep the socket open for the caller to use
     454             :                  */
     455       17710 :                 return;
     456             :         }
     457             : 
     458       17716 :         if (state->sock != -1) {
     459           0 :                 close(state->sock);
     460           0 :                 state->sock = -1;
     461             :         }
     462             : 
     463       17716 :         return;
     464             : }
     465             : 
     466           2 : static void smbsock_connect_do_139(struct tevent_req *subreq)
     467             : {
     468           2 :         struct tevent_req *req = tevent_req_callback_data(
     469             :                 subreq, struct tevent_req);
     470           2 :         struct smbsock_connect_state *state = tevent_req_data(
     471             :                 req, struct smbsock_connect_state);
     472           0 :         bool ret;
     473             : 
     474           2 :         ret = tevent_wakeup_recv(subreq);
     475           2 :         TALLOC_FREE(subreq);
     476           2 :         if (!ret) {
     477           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     478           0 :                 return;
     479             :         }
     480           4 :         state->req_139 = nb_connect_send(state, state->ev, state->addr,
     481             :                                          state->called_name,
     482           2 :                                          state->called_type,
     483             :                                          state->calling_name,
     484           2 :                                          state->calling_type);
     485           2 :         if (tevent_req_nomem(state->req_139, req)) {
     486           0 :                 return;
     487             :         }
     488           2 :         tevent_req_set_callback(state->req_139, smbsock_connect_connected,
     489             :                                 req);
     490             : }
     491             : 
     492       17714 : static void smbsock_connect_connected(struct tevent_req *subreq)
     493             : {
     494       17714 :         struct tevent_req *req = tevent_req_callback_data(
     495             :                 subreq, struct tevent_req);
     496       17714 :         struct smbsock_connect_state *state = tevent_req_data(
     497             :                 req, struct smbsock_connect_state);
     498           0 :         struct tevent_req *unfinished_req;
     499           0 :         NTSTATUS status;
     500             : 
     501       17714 :         if (subreq == state->req_445) {
     502             : 
     503       16673 :                 status = open_socket_out_recv(subreq, &state->sock);
     504       16673 :                 TALLOC_FREE(state->req_445);
     505       16673 :                 unfinished_req = state->req_139;
     506       16673 :                 state->port = TCP_SMB_PORT;
     507             : 
     508        1041 :         } else if (subreq == state->req_139) {
     509             : 
     510        1041 :                 status = nb_connect_recv(subreq, &state->sock);
     511        1041 :                 TALLOC_FREE(state->req_139);
     512        1041 :                 unfinished_req = state->req_445;
     513        1041 :                 state->port = NBT_SMB_PORT;
     514             : 
     515             :         } else {
     516           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     517           0 :                 return;
     518             :         }
     519             : 
     520       17714 :         if (NT_STATUS_IS_OK(status)) {
     521       17710 :                 TALLOC_FREE(unfinished_req);
     522       17710 :                 state->req_139 = NULL;
     523       17710 :                 state->req_445 = NULL;
     524       17710 :                 tevent_req_done(req);
     525       17710 :                 return;
     526             :         }
     527           4 :         if (unfinished_req == NULL) {
     528             :                 /*
     529             :                  * Both requests failed
     530             :                  */
     531           2 :                 tevent_req_nterror(req, status);
     532           2 :                 return;
     533             :         }
     534             :         /*
     535             :          * Do nothing, wait for the second request to come here.
     536             :          */
     537             : }
     538             : 
     539       17712 : NTSTATUS smbsock_connect_recv(struct tevent_req *req, int *sock,
     540             :                               uint16_t *ret_port)
     541             : {
     542       17712 :         struct smbsock_connect_state *state = tevent_req_data(
     543             :                 req, struct smbsock_connect_state);
     544           0 :         NTSTATUS status;
     545             : 
     546       17712 :         if (tevent_req_is_nterror(req, &status)) {
     547           2 :                 tevent_req_received(req);
     548           2 :                 return status;
     549             :         }
     550       17710 :         *sock = state->sock;
     551       17710 :         state->sock = -1;
     552       17710 :         if (ret_port != NULL) {
     553       17708 :                 *ret_port = state->port;
     554             :         }
     555       17710 :         tevent_req_received(req);
     556       17710 :         return NT_STATUS_OK;
     557             : }
     558             : 
     559           2 : NTSTATUS smbsock_connect(const struct sockaddr_storage *addr, uint16_t port,
     560             :                          const char *called_name, int called_type,
     561             :                          const char *calling_name, int calling_type,
     562             :                          int *pfd, uint16_t *ret_port, int sec_timeout)
     563             : {
     564           2 :         TALLOC_CTX *frame = talloc_stackframe();
     565           0 :         struct tevent_context *ev;
     566           0 :         struct tevent_req *req;
     567           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     568             : 
     569           2 :         ev = samba_tevent_context_init(frame);
     570           2 :         if (ev == NULL) {
     571           0 :                 goto fail;
     572             :         }
     573           2 :         req = smbsock_connect_send(frame, ev, addr, port,
     574             :                                    called_name, called_type,
     575             :                                    calling_name, calling_type);
     576           2 :         if (req == NULL) {
     577           0 :                 goto fail;
     578             :         }
     579           2 :         if ((sec_timeout != 0) &&
     580           2 :             !tevent_req_set_endtime(
     581             :                     req, ev, timeval_current_ofs(sec_timeout, 0))) {
     582           0 :                 goto fail;
     583             :         }
     584           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     585           0 :                 goto fail;
     586             :         }
     587           2 :         status = smbsock_connect_recv(req, pfd, ret_port);
     588           2 :  fail:
     589           2 :         TALLOC_FREE(frame);
     590           2 :         return status;
     591             : }
     592             : 
     593             : struct smbsock_any_connect_state {
     594             :         struct tevent_context *ev;
     595             :         const struct sockaddr_storage *addrs;
     596             :         const char **called_names;
     597             :         int *called_types;
     598             :         const char **calling_names;
     599             :         int *calling_types;
     600             :         size_t num_addrs;
     601             :         uint16_t port;
     602             : 
     603             :         struct tevent_req **requests;
     604             :         size_t num_sent;
     605             :         size_t num_received;
     606             : 
     607             :         int fd;
     608             :         uint16_t chosen_port;
     609             :         size_t chosen_index;
     610             : };
     611             : 
     612             : static void smbsock_any_connect_cleanup(struct tevent_req *req,
     613             :                                         enum tevent_req_state req_state);
     614             : static bool smbsock_any_connect_send_next(
     615             :         struct tevent_req *req, struct smbsock_any_connect_state *state);
     616             : static void smbsock_any_connect_trynext(struct tevent_req *subreq);
     617             : static void smbsock_any_connect_connected(struct tevent_req *subreq);
     618             : 
     619       17710 : struct tevent_req *smbsock_any_connect_send(TALLOC_CTX *mem_ctx,
     620             :                                             struct tevent_context *ev,
     621             :                                             const struct sockaddr_storage *addrs,
     622             :                                             const char **called_names,
     623             :                                             int *called_types,
     624             :                                             const char **calling_names,
     625             :                                             int *calling_types,
     626             :                                             size_t num_addrs, uint16_t port)
     627             : {
     628           0 :         struct tevent_req *req, *subreq;
     629           0 :         struct smbsock_any_connect_state *state;
     630             : 
     631       17710 :         req = tevent_req_create(mem_ctx, &state,
     632             :                                 struct smbsock_any_connect_state);
     633       17710 :         if (req == NULL) {
     634           0 :                 return NULL;
     635             :         }
     636       17710 :         state->ev = ev;
     637       17710 :         state->addrs = addrs;
     638       17710 :         state->num_addrs = num_addrs;
     639       17710 :         state->called_names = called_names;
     640       17710 :         state->called_types = called_types;
     641       17710 :         state->calling_names = calling_names;
     642       17710 :         state->calling_types = calling_types;
     643       17710 :         state->port = port;
     644       17710 :         state->fd = -1;
     645             : 
     646       17710 :         tevent_req_set_cleanup_fn(req, smbsock_any_connect_cleanup);
     647             : 
     648       17710 :         if (num_addrs == 0) {
     649           0 :                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
     650           0 :                 return tevent_req_post(req, ev);
     651             :         }
     652             : 
     653       17710 :         state->requests = talloc_zero_array(state, struct tevent_req *,
     654             :                                             num_addrs);
     655       17710 :         if (tevent_req_nomem(state->requests, req)) {
     656           0 :                 return tevent_req_post(req, ev);
     657             :         }
     658       17710 :         if (!smbsock_any_connect_send_next(req, state)) {
     659           0 :                 return tevent_req_post(req, ev);
     660             :         }
     661       17710 :         if (state->num_sent >= state->num_addrs) {
     662        9502 :                 return req;
     663             :         }
     664        8208 :         subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0, 10000));
     665        8208 :         if (tevent_req_nomem(subreq, req)) {
     666           0 :                 return tevent_req_post(req, ev);
     667             :         }
     668        8208 :         tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
     669        8208 :         return req;
     670             : }
     671             : 
     672       35420 : static void smbsock_any_connect_cleanup(struct tevent_req *req,
     673             :                                         enum tevent_req_state req_state)
     674             : {
     675       35420 :         struct smbsock_any_connect_state *state = tevent_req_data(
     676             :                 req, struct smbsock_any_connect_state);
     677             : 
     678       35420 :         TALLOC_FREE(state->requests);
     679             : 
     680       35420 :         if (req_state == TEVENT_REQ_DONE) {
     681             :                 /*
     682             :                  * Keep the socket open for the caller.
     683             :                  */
     684       17708 :                 return;
     685             :         }
     686             : 
     687       17712 :         if (state->fd != -1) {
     688           0 :                 close(state->fd);
     689           0 :                 state->fd = -1;
     690             :         }
     691             : }
     692             : 
     693           2 : static void smbsock_any_connect_trynext(struct tevent_req *subreq)
     694             : {
     695           2 :         struct tevent_req *req = tevent_req_callback_data(
     696             :                 subreq, struct tevent_req);
     697           2 :         struct smbsock_any_connect_state *state = tevent_req_data(
     698             :                 req, struct smbsock_any_connect_state);
     699           0 :         bool ret;
     700             : 
     701           2 :         ret = tevent_wakeup_recv(subreq);
     702           2 :         TALLOC_FREE(subreq);
     703           2 :         if (!ret) {
     704           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     705           0 :                 return;
     706             :         }
     707           2 :         if (!smbsock_any_connect_send_next(req, state)) {
     708           0 :                 return;
     709             :         }
     710           2 :         if (state->num_sent >= state->num_addrs) {
     711           2 :                 return;
     712             :         }
     713           0 :         subreq = tevent_wakeup_send(state, state->ev,
     714             :                                     tevent_timeval_set(0, 10000));
     715           0 :         if (tevent_req_nomem(subreq, req)) {
     716           0 :                 return;
     717             :         }
     718           0 :         tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
     719             : }
     720             : 
     721       17712 : static bool smbsock_any_connect_send_next(
     722             :         struct tevent_req *req, struct smbsock_any_connect_state *state)
     723             : {
     724           0 :         struct tevent_req *subreq;
     725             : 
     726       17712 :         if (state->num_sent >= state->num_addrs) {
     727           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     728           0 :                 return false;
     729             :         }
     730       17716 :         subreq = smbsock_connect_send(
     731       17712 :                 state->requests, state->ev, &state->addrs[state->num_sent],
     732       17712 :                 state->port,
     733       17712 :                 (state->called_names != NULL)
     734       17712 :                 ? state->called_names[state->num_sent] : NULL,
     735       17712 :                 (state->called_types != NULL)
     736       17710 :                 ? state->called_types[state->num_sent] : -1,
     737       17712 :                 (state->calling_names != NULL)
     738       17710 :                 ? state->calling_names[state->num_sent] : NULL,
     739       17712 :                 (state->calling_types != NULL)
     740           0 :                 ? state->calling_types[state->num_sent] : -1);
     741       17712 :         if (tevent_req_nomem(subreq, req)) {
     742           0 :                 return false;
     743             :         }
     744       17712 :         tevent_req_set_callback(subreq, smbsock_any_connect_connected, req);
     745             : 
     746       17712 :         state->requests[state->num_sent] = subreq;
     747       17712 :         state->num_sent += 1;
     748             : 
     749       17712 :         return true;
     750             : }
     751             : 
     752       17710 : static void smbsock_any_connect_connected(struct tevent_req *subreq)
     753             : {
     754       17710 :         struct tevent_req *req = tevent_req_callback_data(
     755             :                 subreq, struct tevent_req);
     756       17710 :         struct smbsock_any_connect_state *state = tevent_req_data(
     757             :                 req, struct smbsock_any_connect_state);
     758           0 :         NTSTATUS status;
     759       17710 :         int fd = 0;
     760       17710 :         uint16_t chosen_port = 0;
     761           0 :         size_t i;
     762       17710 :         size_t chosen_index = 0;
     763             : 
     764       17710 :         for (i=0; i<state->num_sent; i++) {
     765       17710 :                 if (state->requests[i] == subreq) {
     766       17710 :                         chosen_index = i;
     767       17710 :                         break;
     768             :                 }
     769             :         }
     770       17710 :         if (i == state->num_sent) {
     771           0 :                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
     772           0 :                 return;
     773             :         }
     774             : 
     775       17710 :         status = smbsock_connect_recv(subreq, &fd, &chosen_port);
     776             : 
     777       17710 :         TALLOC_FREE(subreq);
     778       17710 :         state->requests[chosen_index] = NULL;
     779             : 
     780       17710 :         if (NT_STATUS_IS_OK(status)) {
     781             :                 /*
     782             :                  * tevent_req_done() will kill all the other requests
     783             :                  * via smbsock_any_connect_cleanup().
     784             :                  */
     785       17708 :                 state->fd = fd;
     786       17708 :                 state->chosen_port = chosen_port;
     787       17708 :                 state->chosen_index = chosen_index;
     788       17708 :                 tevent_req_done(req);
     789       17708 :                 return;
     790             :         }
     791             : 
     792           2 :         state->num_received += 1;
     793           2 :         if (state->num_received < state->num_addrs) {
     794             :                 /*
     795             :                  * More addrs pending, wait for the others
     796             :                  */
     797           0 :                 return;
     798             :         }
     799             : 
     800             :         /*
     801             :          * This is the last response, none succeeded.
     802             :          */
     803           2 :         tevent_req_nterror(req, status);
     804           2 :         return;
     805             : }
     806             : 
     807       17710 : NTSTATUS smbsock_any_connect_recv(struct tevent_req *req, int *pfd,
     808             :                                   size_t *chosen_index,
     809             :                                   uint16_t *chosen_port)
     810             : {
     811       17710 :         struct smbsock_any_connect_state *state = tevent_req_data(
     812             :                 req, struct smbsock_any_connect_state);
     813           0 :         NTSTATUS status;
     814             : 
     815       17710 :         if (tevent_req_is_nterror(req, &status)) {
     816           2 :                 tevent_req_received(req);
     817           2 :                 return status;
     818             :         }
     819       17708 :         *pfd = state->fd;
     820       17708 :         state->fd = -1;
     821       17708 :         if (chosen_index != NULL) {
     822           2 :                 *chosen_index = state->chosen_index;
     823             :         }
     824       17708 :         if (chosen_port != NULL) {
     825       17706 :                 *chosen_port = state->chosen_port;
     826             :         }
     827       17708 :         tevent_req_received(req);
     828       17708 :         return NT_STATUS_OK;
     829             : }
     830             : 
     831           2 : NTSTATUS smbsock_any_connect(const struct sockaddr_storage *addrs,
     832             :                              const char **called_names,
     833             :                              int *called_types,
     834             :                              const char **calling_names,
     835             :                              int *calling_types,
     836             :                              size_t num_addrs,
     837             :                              uint16_t port,
     838             :                              int sec_timeout,
     839             :                              int *pfd, size_t *chosen_index,
     840             :                              uint16_t *chosen_port)
     841             : {
     842           2 :         TALLOC_CTX *frame = talloc_stackframe();
     843           0 :         struct tevent_context *ev;
     844           0 :         struct tevent_req *req;
     845           2 :         NTSTATUS status = NT_STATUS_NO_MEMORY;
     846             : 
     847           2 :         ev = samba_tevent_context_init(frame);
     848           2 :         if (ev == NULL) {
     849           0 :                 goto fail;
     850             :         }
     851           2 :         req = smbsock_any_connect_send(frame, ev, addrs,
     852             :                                        called_names, called_types,
     853             :                                        calling_names, calling_types,
     854             :                                        num_addrs, port);
     855           2 :         if (req == NULL) {
     856           0 :                 goto fail;
     857             :         }
     858           2 :         if ((sec_timeout != 0) &&
     859           2 :             !tevent_req_set_endtime(
     860             :                     req, ev, timeval_current_ofs(sec_timeout, 0))) {
     861           0 :                 goto fail;
     862             :         }
     863           2 :         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
     864           0 :                 goto fail;
     865             :         }
     866           2 :         status = smbsock_any_connect_recv(req, pfd, chosen_index, chosen_port);
     867           2 :  fail:
     868           2 :         TALLOC_FREE(frame);
     869           2 :         return status;
     870             : }

Generated by: LCOV version 1.14