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

Generated by: LCOV version 1.13