s3:libsmb: move cli_session_request*() to smbsock_connect.c
[samba.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 "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 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 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, 139, 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                                               139, 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, *subreq;
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 == 139) {
355                 subreq = tevent_wakeup_send(state, ev, timeval_set(0, 0));
356                 if (tevent_req_nomem(subreq, req)) {
357                         return tevent_req_post(req, ev);
358                 }
359                 tevent_req_set_callback(subreq, smbsock_connect_do_139, req);
360                 return req;
361         }
362         if (port != 0) {
363                 state->req_445 = open_socket_out_send(state, ev, addr, port,
364                                                       5000);
365                 if (tevent_req_nomem(state->req_445, req)) {
366                         return tevent_req_post(req, ev);
367                 }
368                 tevent_req_set_callback(
369                         state->req_445, smbsock_connect_connected, req);
370                 return req;
371         }
372
373         /*
374          * port==0, try both
375          */
376
377         state->req_445 = open_socket_out_send(state, ev, addr, 445, 5000);
378         if (tevent_req_nomem(state->req_445, req)) {
379                 return tevent_req_post(req, ev);
380         }
381         tevent_req_set_callback(state->req_445, smbsock_connect_connected,
382                                 req);
383
384         /*
385          * After 5 msecs, fire the 139 request
386          */
387         state->req_139 = tevent_wakeup_send(
388                 state, ev, timeval_current_ofs(0, 5000));
389         if (tevent_req_nomem(state->req_139, req)) {
390                 TALLOC_FREE(state->req_445);
391                 return tevent_req_post(req, ev);
392         }
393         tevent_req_set_callback(state->req_139, smbsock_connect_do_139,
394                                 req);
395         return req;
396 }
397
398 static int smbsock_connect_state_destructor(
399         struct smbsock_connect_state *state)
400 {
401         if (state->sock != -1) {
402                 close(state->sock);
403                 state->sock = -1;
404         }
405         return 0;
406 }
407
408 static void smbsock_connect_do_139(struct tevent_req *subreq)
409 {
410         struct tevent_req *req = tevent_req_callback_data(
411                 subreq, struct tevent_req);
412         struct smbsock_connect_state *state = tevent_req_data(
413                 req, struct smbsock_connect_state);
414         bool ret;
415
416         ret = tevent_wakeup_recv(subreq);
417         TALLOC_FREE(subreq);
418         if (!ret) {
419                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
420                 return;
421         }
422         state->req_139 = nb_connect_send(state, state->ev, state->addr,
423                                          state->called_name,
424                                          state->called_type,
425                                          state->calling_name,
426                                          state->calling_type);
427         if (tevent_req_nomem(state->req_139, req)) {
428                 return;
429         }
430         tevent_req_set_callback(state->req_139, smbsock_connect_connected,
431                                 req);
432 }
433
434 static void smbsock_connect_connected(struct tevent_req *subreq)
435 {
436         struct tevent_req *req = tevent_req_callback_data(
437                 subreq, struct tevent_req);
438         struct smbsock_connect_state *state = tevent_req_data(
439                 req, struct smbsock_connect_state);
440         struct tevent_req *unfinished_req;
441         NTSTATUS status;
442
443         if (subreq == state->req_445) {
444
445                 status = open_socket_out_recv(subreq, &state->sock);
446                 TALLOC_FREE(state->req_445);
447                 unfinished_req = state->req_139;
448                 state->port = 445;
449
450         } else if (subreq == state->req_139) {
451
452                 status = nb_connect_recv(subreq, &state->sock);
453                 TALLOC_FREE(state->req_139);
454                 unfinished_req = state->req_445;
455                 state->port = 139;
456
457         } else {
458                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
459                 return;
460         }
461
462         if (NT_STATUS_IS_OK(status)) {
463                 TALLOC_FREE(unfinished_req);
464                 state->req_139 = NULL;
465                 state->req_445 = NULL;
466                 tevent_req_done(req);
467                 return;
468         }
469         if (unfinished_req == NULL) {
470                 /*
471                  * Both requests failed
472                  */
473                 tevent_req_nterror(req, status);
474                 return;
475         }
476         /*
477          * Do nothing, wait for the second request to come here.
478          */
479 }
480
481 NTSTATUS smbsock_connect_recv(struct tevent_req *req, int *sock,
482                               uint16_t *ret_port)
483 {
484         struct smbsock_connect_state *state = tevent_req_data(
485                 req, struct smbsock_connect_state);
486         NTSTATUS status;
487
488         if (tevent_req_is_nterror(req, &status)) {
489                 return status;
490         }
491         *sock = state->sock;
492         state->sock = -1;
493         if (ret_port != NULL) {
494                 *ret_port = state->port;
495         }
496         return NT_STATUS_OK;
497 }
498
499 NTSTATUS smbsock_connect(const struct sockaddr_storage *addr, uint16_t port,
500                          const char *called_name, int called_type,
501                          const char *calling_name, int calling_type,
502                          int *pfd, uint16_t *ret_port, int sec_timeout)
503 {
504         TALLOC_CTX *frame = talloc_stackframe();
505         struct tevent_context *ev;
506         struct tevent_req *req;
507         NTSTATUS status = NT_STATUS_NO_MEMORY;
508
509         ev = tevent_context_init(frame);
510         if (ev == NULL) {
511                 goto fail;
512         }
513         req = smbsock_connect_send(frame, ev, addr, port,
514                                    called_name, called_type,
515                                    calling_name, calling_type);
516         if (req == NULL) {
517                 goto fail;
518         }
519         if ((sec_timeout != 0) &&
520             !tevent_req_set_endtime(
521                     req, ev, timeval_current_ofs(sec_timeout, 0))) {
522                 goto fail;
523         }
524         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
525                 goto fail;
526         }
527         status = smbsock_connect_recv(req, pfd, ret_port);
528  fail:
529         TALLOC_FREE(frame);
530         return status;
531 }
532
533 struct smbsock_any_connect_state {
534         struct tevent_context *ev;
535         const struct sockaddr_storage *addrs;
536         const char **called_names;
537         int *called_types;
538         const char **calling_names;
539         int *calling_types;
540         size_t num_addrs;
541         uint16_t port;
542
543         struct tevent_req **requests;
544         size_t num_sent;
545         size_t num_received;
546
547         int fd;
548         uint16_t chosen_port;
549         size_t chosen_index;
550 };
551
552 static bool smbsock_any_connect_send_next(
553         struct tevent_req *req, struct smbsock_any_connect_state *state);
554 static void smbsock_any_connect_trynext(struct tevent_req *subreq);
555 static void smbsock_any_connect_connected(struct tevent_req *subreq);
556
557 struct tevent_req *smbsock_any_connect_send(TALLOC_CTX *mem_ctx,
558                                             struct tevent_context *ev,
559                                             const struct sockaddr_storage *addrs,
560                                             const char **called_names,
561                                             int *called_types,
562                                             const char **calling_names,
563                                             int *calling_types,
564                                             size_t num_addrs, uint16_t port)
565 {
566         struct tevent_req *req, *subreq;
567         struct smbsock_any_connect_state *state;
568
569         req = tevent_req_create(mem_ctx, &state,
570                                 struct smbsock_any_connect_state);
571         if (req == NULL) {
572                 return NULL;
573         }
574         state->ev = ev;
575         state->addrs = addrs;
576         state->num_addrs = num_addrs;
577         state->called_names = called_names;
578         state->called_types = called_types;
579         state->calling_names = calling_names;
580         state->calling_types = calling_types;
581         state->port = port;
582
583         if (num_addrs == 0) {
584                 tevent_req_nterror(req, NT_STATUS_INVALID_PARAMETER);
585                 return tevent_req_post(req, ev);
586         }
587
588         state->requests = talloc_zero_array(state, struct tevent_req *,
589                                             num_addrs);
590         if (tevent_req_nomem(state->requests, req)) {
591                 return tevent_req_post(req, ev);
592         }
593         if (!smbsock_any_connect_send_next(req, state)) {
594                 return tevent_req_post(req, ev);
595         }
596         if (state->num_sent >= state->num_addrs) {
597                 return req;
598         }
599         subreq = tevent_wakeup_send(state, ev, timeval_current_ofs(0, 10000));
600         if (tevent_req_nomem(subreq, req)) {
601                 return tevent_req_post(req, ev);
602         }
603         tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
604         return req;
605 }
606
607 static void smbsock_any_connect_trynext(struct tevent_req *subreq)
608 {
609         struct tevent_req *req = tevent_req_callback_data(
610                 subreq, struct tevent_req);
611         struct smbsock_any_connect_state *state = tevent_req_data(
612                 req, struct smbsock_any_connect_state);
613         bool ret;
614
615         ret = tevent_wakeup_recv(subreq);
616         TALLOC_FREE(subreq);
617         if (!ret) {
618                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
619                 return;
620         }
621         if (!smbsock_any_connect_send_next(req, state)) {
622                 return;
623         }
624         if (state->num_sent >= state->num_addrs) {
625                 return;
626         }
627         subreq = tevent_wakeup_send(state, state->ev,
628                                     tevent_timeval_set(0, 10000));
629         if (tevent_req_nomem(subreq, req)) {
630                 return;
631         }
632         tevent_req_set_callback(subreq, smbsock_any_connect_trynext, req);
633 }
634
635 static bool smbsock_any_connect_send_next(
636         struct tevent_req *req, struct smbsock_any_connect_state *state)
637 {
638         struct tevent_req *subreq;
639
640         if (state->num_sent >= state->num_addrs) {
641                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
642                 return false;
643         }
644         subreq = smbsock_connect_send(
645                 state->requests, state->ev, &state->addrs[state->num_sent],
646                 state->port,
647                 (state->called_names != NULL)
648                 ? state->called_names[state->num_sent] : NULL,
649                 (state->called_types != NULL)
650                 ? state->called_types[state->num_sent] : -1,
651                 (state->calling_names != NULL)
652                 ? state->calling_names[state->num_sent] : NULL,
653                 (state->calling_types != NULL)
654                 ? state->calling_types[state->num_sent] : -1);
655         if (tevent_req_nomem(subreq, req)) {
656                 return false;
657         }
658         tevent_req_set_callback(subreq, smbsock_any_connect_connected, req);
659
660         state->requests[state->num_sent] = subreq;
661         state->num_sent += 1;
662
663         return true;
664 }
665
666 static void smbsock_any_connect_connected(struct tevent_req *subreq)
667 {
668         struct tevent_req *req = tevent_req_callback_data(
669                 subreq, struct tevent_req);
670         struct smbsock_any_connect_state *state = tevent_req_data(
671                 req, struct smbsock_any_connect_state);
672         NTSTATUS status;
673         int fd;
674         uint16_t chosen_port;
675         size_t i;
676         size_t chosen_index = 0;
677
678         for (i=0; i<state->num_sent; i++) {
679                 if (state->requests[i] == subreq) {
680                         chosen_index = i;
681                         break;
682                 }
683         }
684         if (i == state->num_sent) {
685                 tevent_req_nterror(req, NT_STATUS_INTERNAL_ERROR);
686                 return;
687         }
688
689         status = smbsock_connect_recv(subreq, &fd, &chosen_port);
690
691         TALLOC_FREE(subreq);
692         state->requests[chosen_index] = NULL;
693
694         if (NT_STATUS_IS_OK(status)) {
695                 /*
696                  * This will kill all the other requests
697                  */
698                 TALLOC_FREE(state->requests);
699                 state->fd = fd;
700                 state->chosen_port = chosen_port;
701                 state->chosen_index = chosen_index;
702                 tevent_req_done(req);
703                 return;
704         }
705
706         state->num_received += 1;
707         if (state->num_received < state->num_addrs) {
708                 /*
709                  * More addrs pending, wait for the others
710                  */
711                 return;
712         }
713
714         /*
715          * This is the last response, none succeeded.
716          */
717         tevent_req_nterror(req, status);
718         return;
719 }
720
721 NTSTATUS smbsock_any_connect_recv(struct tevent_req *req, int *pfd,
722                                   size_t *chosen_index,
723                                   uint16_t *chosen_port)
724 {
725         struct smbsock_any_connect_state *state = tevent_req_data(
726                 req, struct smbsock_any_connect_state);
727         NTSTATUS status;
728
729         if (tevent_req_is_nterror(req, &status)) {
730                 return status;
731         }
732         *pfd = state->fd;
733         if (chosen_index != NULL) {
734                 *chosen_index = state->chosen_index;
735         }
736         if (chosen_port != NULL) {
737                 *chosen_port = state->chosen_port;
738         }
739         return NT_STATUS_OK;
740 }
741
742 NTSTATUS smbsock_any_connect(const struct sockaddr_storage *addrs,
743                              const char **called_names,
744                              int *called_types,
745                              const char **calling_names,
746                              int *calling_types,
747                              size_t num_addrs,
748                              uint16_t port,
749                              int sec_timeout,
750                              int *pfd, size_t *chosen_index,
751                              uint16_t *chosen_port)
752 {
753         TALLOC_CTX *frame = talloc_stackframe();
754         struct tevent_context *ev;
755         struct tevent_req *req;
756         NTSTATUS status = NT_STATUS_NO_MEMORY;
757
758         ev = tevent_context_init(frame);
759         if (ev == NULL) {
760                 goto fail;
761         }
762         req = smbsock_any_connect_send(frame, ev, addrs,
763                                        called_names, called_types,
764                                        calling_names, calling_types,
765                                        num_addrs, port);
766         if (req == NULL) {
767                 goto fail;
768         }
769         if ((sec_timeout != 0) &&
770             !tevent_req_set_endtime(
771                     req, ev, timeval_current_ofs(sec_timeout, 0))) {
772                 goto fail;
773         }
774         if (!tevent_req_poll_ntstatus(req, ev, &status)) {
775                 goto fail;
776         }
777         status = smbsock_any_connect_recv(req, pfd, chosen_index, chosen_port);
778  fail:
779         TALLOC_FREE(frame);
780         return status;
781 }