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