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